Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ public int toProtoValue() {
return version;
}

public int getVersion() {
return version;
}

public static ClientVersion fromProtoValue(int value) {
return BY_PROTO_VALUE.getOrDefault(value, FUTURE_VERSION);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,13 +301,20 @@ private OMRequest.Builder createOMRequest(Type cmdType) {
.setClientId(clientID);
}

@VisibleForTesting
public OMRequest.Builder createOMRequest(Type cmdType, int clientVersion) {
return OMRequest.newBuilder().setCmdType(cmdType).setVersion(clientVersion)
.setClientId(clientID);
}

/**
* Submits client request to OM server.
* @param omRequest client request
* @return response from OM
* @throws IOException thrown if any Protobuf service exception occurs
*/
private OMResponse submitRequest(OMRequest omRequest)
@VisibleForTesting
public OMResponse submitRequest(OMRequest omRequest)
throws IOException {
OMRequest.Builder builder = OMRequest.newBuilder(omRequest);
// Insert S3 Authentication information for each request.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,30 @@
import org.apache.hadoop.ozone.client.OzoneKey;
import org.apache.hadoop.ozone.client.OzoneKeyDetails;
import org.apache.hadoop.ozone.client.OzoneVolume;
import org.apache.hadoop.ozone.ClientVersion;
import org.apache.hadoop.ozone.client.BucketArgs;
import org.apache.hadoop.ozone.client.io.KeyOutputStream;
import org.apache.hadoop.ozone.client.io.OzoneInputStream;
import org.apache.hadoop.ozone.client.io.OzoneOutputStream;
import org.apache.hadoop.ozone.client.rpc.RpcClient;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus;
import org.apache.hadoop.ozone.om.helpers.OmKeyArgs;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
import org.apache.hadoop.ozone.om.protocolPB.OzoneManagerProtocolClientSideTranslatorPB;
import org.apache.hadoop.util.StringUtils;
import org.apache.ozone.test.GenericTestUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.Arguments;

import java.io.IOException;
import java.net.URI;
Expand All @@ -64,6 +73,7 @@
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;

import static org.apache.hadoop.hdds.client.ReplicationFactor.ONE;
import static org.apache.hadoop.hdds.client.ReplicationType.RATIS;
Expand All @@ -72,6 +82,7 @@
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_SCHEME;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.KEY_ALREADY_EXISTS;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.KEY_NOT_FOUND;
import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status.OK;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
Expand All @@ -94,6 +105,8 @@ public class TestObjectStoreWithFSO {
private static FileSystem fs;
private static OzoneClient client;

private static OzoneManagerProtocolClientSideTranslatorPB ozoneManagerClient;

/**
* Create a MiniDFSCluster for testing.
* <p>
Expand All @@ -108,6 +121,9 @@ public static void init() throws Exception {
cluster = MiniOzoneCluster.newBuilder(conf).build();
cluster.waitForClusterToBeReady();
client = cluster.newClient();
ozoneManagerClient =
(OzoneManagerProtocolClientSideTranslatorPB)
((RpcClient) client.getObjectStore().getClientProxy()).getOzoneManagerClient();
// create a volume and a bucket to be used by OzoneFileSystem
OzoneBucket bucket = TestDataUtil
.createVolumeAndBucket(client, BucketLayout.FILE_SYSTEM_OPTIMIZED);
Expand Down Expand Up @@ -210,6 +226,76 @@ public void testCreateKey() throws Exception {
dirPathC.getObjectID(), true);
}

public OzoneFileStatus getFileStatus(OmKeyArgs args, int clientVersion)
throws IOException {
OzoneManagerProtocolProtos.KeyArgs keyArgs =
OzoneManagerProtocolProtos.KeyArgs.newBuilder()
.setVolumeName(args.getVolumeName())
.setBucketName(args.getBucketName()).setKeyName(args.getKeyName())
.build();
OzoneManagerProtocolProtos.GetFileStatusRequest req =
OzoneManagerProtocolProtos.GetFileStatusRequest.newBuilder()
.setKeyArgs(keyArgs).build();
OzoneManagerProtocolProtos.OMRequest omRequest =
ozoneManagerClient.createOMRequest(
OzoneManagerProtocolProtos.Type.GetFileStatus, clientVersion)
.setGetFileStatusRequest(req).build();
OzoneManagerProtocolProtos.GetFileStatusResponse resp;
try {
OzoneManagerProtocolProtos.OMResponse omResponse =
ozoneManagerClient.submitRequest(omRequest);
if (omResponse.getStatus() != OK) {
throw new OMException(omResponse.getMessage(),
OMException.ResultCodes.values()[omResponse.getStatus().ordinal()]);
}
resp = omResponse.getGetFileStatusResponse();
} catch (IOException e) {
throw e;
}
OzoneFileStatus getFileStatusResp =
OzoneFileStatus.getFromProtobuf(resp.getStatus());
return getFileStatusResp;
}


private static Stream<Arguments> allClientVersions() {
return Arrays.stream(ClientVersion.values())
.map(clientVersion -> Arguments.of(clientVersion.getVersion()));
}
@ParameterizedTest
@MethodSource("allClientVersions")
public void testGetFileStatusFromOlderClients(int clientVersion) throws Exception {
// try to create key from new client
String parent = "a/b/c/";
String file = "key1" + RandomStringUtils.randomNumeric(5);
String key = parent + file;

ObjectStore objectStore = client.getObjectStore();
OzoneVolume ozoneVolume = objectStore.getVolume(volumeName);
assertEquals(volumeName, ozoneVolume.getName());
OzoneBucket ozoneBucket = ozoneVolume.getBucket(bucketName);
assertEquals(bucketName, ozoneBucket.getName());
String data = "random data";
try (OzoneOutputStream ozoneOutputStream = ozoneBucket.createKey(key,
data.length(), ReplicationType.RATIS, ReplicationFactor.ONE,
new HashMap<>())) {
ozoneOutputStream.write(data.getBytes(StandardCharsets.UTF_8));
}
// try to read from older client
OmKeyArgs keyArgs = new OmKeyArgs.Builder()
.setVolumeName(ozoneBucket.getVolumeName())
.setBucketName(ozoneBucket.getName())
.setKeyName(key)
.build();
if (clientVersion < ClientVersion.BUCKET_LAYOUT_SUPPORT.getVersion()) {
assertThrows(OMException.class,
() -> getFileStatus(keyArgs, clientVersion),
"Expecting Unsupported Operation Exception");
} else {
assertNotNull(getFileStatus(keyArgs, clientVersion));
}
}

/**
* Tests bucket deletion behaviour. Buckets should not be allowed to be
* deleted if they contain files or directories under them.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ public static OMRequest handleCreateBucketWithBucketLayoutDuringPreFinalize(
* they do not understand.
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this different than what is happening on lines 469-470?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With Ozone 1.4.0, client supports bucket layout. The feature validator is wrongly rejecting the request.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rejection does not happen in the annotation. The annotation determines when the method should be called. In this case this method is called when we get an older client request. That's why the method to check the condition is called shouldApply. The body of the method determines whether to reject or modify the request. The body of the method has a more specific check for specific client version.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have multiple such validations, this method takes care but other methods don't.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The annotation determines when the method should be called. In this case this method is called when we get an older client request. That's why the method to check the condition is called shouldApply. The body of the method determines whether to reject or modify the request.

It's very confusing for both the annotation and the method to have conditions. If the method checks the client request anyway, it can be called regardless of client version.

Copy link
Contributor

@errose28 errose28 Jul 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I also suggested a refactor, but in a follow up. The refactor done here is not good because it requires updates to two enums for each client layout version.

Ideally all the compat requirements would be specified in the annotation

processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.CreateBucket
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ private boolean bucketContainsSnapshotInCache(
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.DeleteBucket
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ public static OMRequest disallowCreateDirectoryWithECReplicationConfig(
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.CreateDirectory
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ public static OMRequest disallowCreateFileWithECReplicationConfig(
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.CreateFile
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ public static OMRequest disallowAllocateBlockWithECReplicationConfig(
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.AllocateBlock
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ public static OMRequest disallowCommitKeyWithECReplicationConfig(
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.CommitKey
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ public static OMRequest disallowCreateKeyWithECReplicationConfig(
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.CreateKey
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.DeleteKey
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ private Map<String, String> buildAuditMap(
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.RenameKey
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ protected static void addDeletedKeys(Map<String, String> auditMap,
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.DeleteKeys
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ private Map<String, String> buildAuditMap(Map<String, String> auditMap,
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.RenameKeys
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.AddAcl
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.RemoveAcl
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.SetAcl
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ protected void logResult(OzoneManager ozoneManager,
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.InitiateMultiPartUpload
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ public static OMRequest disallowAbortMultiPartUploadWithECReplicationConfig(
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.AbortMultiPartUpload
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ public static OMRequest disallowCommitMultiPartUploadWithECReplicationConfig(
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.CommitMultiPartUpload
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ private void updateCache(OMMetadataManager omMetadataManager,
* @throws OMException if the request is invalid
*/
@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
conditions = ValidationCondition.OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.PRE_PROCESS,
requestType = Type.CompleteMultiPartUpload
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,13 @@ public boolean shouldApply(OMRequest req, ValidationContext ctx) {

/**
* Classifies validations that has to run, when the client uses an older
* protocol version than the server.
* protocol version than the bucket layout version i.e the version where
* bucket types where introduced.
*/
OLDER_CLIENT_REQUESTS {
OLDER_BUCKET_LAYOUT_CLIENT_REQUESTS {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@errose28 This fixes the issue.

@Override
public boolean shouldApply(OMRequest req, ValidationContext ctx) {
return req.getVersion() < ClientVersion.CURRENT_VERSION;
return req.getVersion() < ClientVersion.BUCKET_LAYOUT_SUPPORT.getVersion();
}
};

Expand Down
Loading