Skip to content

HDDS-8547. Support Trash for FSO bucket using ozone sh command. #4675

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from 9 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
2 changes: 1 addition & 1 deletion hadoop-ozone/dist/src/main/smoketest/basic/links.robot
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ Key list passthrough
Should Contain ${source_list} key2

Key delete passthrough
Execute ozone sh key delete ${target}/link1/key2
Execute ozone sh key delete --skipTrash ${target}/link1/key2
${source_list} = Execute ozone sh key list ${source}/bucket1 | jq -r '.[].name'
Should Not Contain ${source_list} key2

Expand Down
25 changes: 22 additions & 3 deletions hadoop-ozone/dist/src/main/smoketest/basic/ozone-shell-lib.robot
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,13 @@ Test key handling
Execute diff -q /opt/hadoop/NOTICE.txt /tmp/key1_RATIS
${result} = Execute ozone sh key info ${protocol}${server}/${volume}/bb1/key1_RATIS | jq -r '. | select(.name=="key1_RATIS")'
Should contain ${result} RATIS
Execute ozone sh key delete ${protocol}${server}/${volume}/bb1/key1_RATIS
Execute ozone sh key delete --skipTrash ${protocol}${server}/${volume}/bb1/key1_RATIS

Execute ozone sh key cp ${protocol}${server}/${volume}/bb1 key1 key1-copy
Execute rm -f /tmp/key1-copy
Execute ozone sh key get ${protocol}${server}/${volume}/bb1/key1-copy /tmp/key1-copy
Execute diff -q /opt/hadoop/NOTICE.txt /tmp/key1-copy
Execute ozone sh key delete ${protocol}${server}/${volume}/bb1/key1-copy
Execute ozone sh key delete --skipTrash ${protocol}${server}/${volume}/bb1/key1-copy

${result} = Execute And Ignore Error ozone sh key get ${protocol}${server}/${volume}/bb1/key1 /tmp/NOTICE.txt.1
Should Contain ${result} NOTICE.txt.1 exists
Expand All @@ -170,7 +170,7 @@ Test key handling
Execute ozone sh key rename ${protocol}${server}/${volume}/bb1 key1 key2
${result} = Execute ozone sh key list ${protocol}${server}/${volume}/bb1 | jq -r '.[].name'
Should Be Equal ${result} key2
Execute ozone sh key delete ${protocol}${server}/${volume}/bb1/key2
Execute ozone sh key delete --skipTrash ${protocol}${server}/${volume}/bb1/key2

Test key Acls
[arguments] ${protocol} ${server} ${volume}
Expand Down Expand Up @@ -204,3 +204,22 @@ Test prefix Acls
${result} = Execute ozone sh key getacl ${protocol}${server}/${volume}/bb1/prefix1/key1
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclScope\" : \"ACCESS\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclScope\" : \"ACCESS\",\n.*\"aclList\" : . \"ALL\" .

Test Delete key with and without Trash
[arguments] ${protocol} ${server} ${volume}
Execute ozone sh volume create ${protocol}${server}/${volume}
Execute ozone sh bucket create ${protocol}${server}/${volume}/bfso --layout FILE_SYSTEM_OPTIMIZED
Execute ozone sh key put -t RATIS ${protocol}${server}/${volume}/bfso/key1 /opt/hadoop/NOTICE.txt
Execute ozone sh key delete --skipTrash ${protocol}${server}/${volume}/bfso/key1
${result} = Execute ozone sh key list ${protocol}${server}/${volume}/bfso
Should not contain ${result} key1
Execute ozone sh bucket create ${protocol}${server}/${volume}/obsbkt --layout OBJECT_STORE
Execute ozone sh key put -t RATIS ${protocol}${server}/${volume}/obsbkt/key2 /opt/hadoop/NOTICE.txt
Execute ozone sh key delete ${protocol}${server}/${volume}/obsbkt/key2
${result} = Execute ozone sh key list ${protocol}${server}/${volume}/obsbkt
Should not contain ${result} key2
Execute ozone sh key put -t RATIS ${protocol}${server}/${volume}/bfso/key3 /opt/hadoop/NOTICE.txt
Execute ozone sh key delete ${protocol}${server}/${volume}/bfso/key3
${result} = Execute ozone sh key list ${protocol}${server}/${volume}/bfso
Should Contain Any ${result} .Trash/hadoop .Trash/testuser .Trash/root
Should contain ${result} key3
4 changes: 4 additions & 0 deletions hadoop-ozone/dist/src/main/smoketest/basic/ozone-shell.robot
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ RpcClient prefix acls

RpcClient without host
Test ozone shell o3:// ${EMPTY} ${prefix}-without-host

RpcClient Delete key
Test Delete key with and without Trash o3:// om:9862 ${prefix}-with-del

Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Create bucket with non-admin owner(testuser2)
Should not contain ${result} PERMISSION_DENIED
${result} = Execute ozone sh key list ${volume4}/bucket1
Should not contain ${result} PERMISSION_DENIED
${result} = Execute ozone sh key delete ${volume4}/bucket1/key1
${result} = Execute ozone sh key delete --skipTrash ${volume4}/bucket1/key1
Should not contain ${result} PERMISSION_DENIED
${result} = Execute ozone sh bucket delete ${volume4}/bucket1
Should not contain ${result} PERMISSION_DENIED
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
Expand Down Expand Up @@ -54,7 +55,9 @@
import org.apache.hadoop.ozone.ha.ConfUtils;
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.OzoneManager;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.hadoop.ozone.shell.s3.S3Shell;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.ozone.test.GenericTestUtils;
import org.apache.ozone.test.LambdaTestUtils;
import org.apache.hadoop.util.ToolRunner;
Expand All @@ -68,6 +71,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY;
import static org.apache.hadoop.fs.FileSystem.FS_DEFAULT_NAME_KEY;
import static org.apache.hadoop.fs.FileSystem.TRASH_PREFIX;
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_OFS_URI_SCHEME;
import org.junit.After;
import org.junit.AfterClass;
Expand Down Expand Up @@ -332,13 +336,17 @@ private String[] getHASetConfStrings(String[] existingArgs) {
/**
* Helper function to generate keys for testing shell command of keys.
*/
private void generateKeys(String volumeName, String bucketName) {
private void generateKeys(String volumeName, String bucketName,
String bucketLayout) {
String[] args = new String[] {
"volume", "create", "o3://" + omServiceId + volumeName};
execute(ozoneShell, args);

args = new String[] {
"bucket", "create", "o3://" + omServiceId + volumeName + bucketName};
args = (Strings.isNullOrEmpty(bucketLayout)) ?
new String[] {"bucket", "create", "o3://" + omServiceId +
volumeName + bucketName } :
new String[] {"bucket", "create", "o3://" + omServiceId +
volumeName + bucketName, "--layout", bucketLayout};
execute(ozoneShell, args);

String keyName = volumeName + bucketName + OZONE_URI_DELIMITER + "key";
Expand Down Expand Up @@ -464,7 +472,7 @@ public void testOzoneShCmdURIs() {
@Test
public void testOzoneShCmdList() throws UnsupportedEncodingException {
// Part of listing keys test.
generateKeys("/volume4", "/bucket");
generateKeys("/volume4", "/bucket", "");
final String destinationBucket = "o3://" + omServiceId + "/volume4/bucket";

// Test case 1: test listing keys
Expand Down Expand Up @@ -516,7 +524,7 @@ public void testOzoneShCmdList() throws UnsupportedEncodingException {
@Test
public void testOzoneAdminCmdList() throws UnsupportedEncodingException {
// Part of listing keys test.
generateKeys("/volume6", "/bucket");
generateKeys("/volume6", "/bucket", "");
// Test case 1: list OPEN container
String state = "--state=OPEN";
String[] args = new String[] {"container", "list", "--scm",
Expand Down Expand Up @@ -1124,6 +1132,167 @@ public void testCreateBucketWithECReplicationConfigWithoutReplicationParam() {
}
}


@Test
public void testKeyDeleteOrSkipTrashWhenTrashEnableFSO()
throws IOException {
// Create 100 keys
generateKeys("/volumefso1", "/bucket1",
BucketLayout.FILE_SYSTEM_OPTIMIZED.toString());

// Enable trash
String trashConfKey = generateSetConfString(
OMConfigKeys.OZONE_FS_TRASH_INTERVAL_KEY, "1");
String[] args =
new String[] {trashConfKey, "key", "delete",
"/volumefso1/bucket1/key4"};

// Delete one key from FSO bucket
execute(ozoneShell, args);

// Get key list in .Trash path
String prefixKey = "--prefix=.Trash";
args = new String[] {"key", "list", prefixKey, "o3://" +
omServiceId + "/volumefso1/bucket1/"};
out.reset();
execute(ozoneShell, args);

// One key should be present in .Trash
Assert.assertEquals(1, getNumOfKeys());

args = new String[] {"key", "list", "o3://" + omServiceId +
"/volumefso1/bucket1/", "-l ", "110"};
out.reset();
execute(ozoneShell, args);

// Total number of keys still 100.
Assert.assertEquals(100, getNumOfKeys());

// Skip Trash
args = new String[] {trashConfKey, "key", "delete",
"/volumefso1/bucket1/key5", "--skipTrash"};
execute(ozoneShell, args);

// .Trash should still contain 1 key
prefixKey = "--prefix=.Trash";
args = new String[] {"key", "list", prefixKey, "o3://" +
omServiceId + "/volumefso1/bucket1/"};
out.reset();
execute(ozoneShell, args);
Assert.assertEquals(1, getNumOfKeys());

args = new String[] {"key", "list", "o3://" + omServiceId +
"/volumefso1/bucket1/", "-l ", "110"};
out.reset();
execute(ozoneShell, args);
// Total number of keys now will be 99 as
// 1 key deleted without trash
Assert.assertEquals(99, getNumOfKeys());

final String username =
UserGroupInformation.getCurrentUser().getShortUserName();
Path trashRoot = new Path(OZONE_URI_DELIMITER, TRASH_PREFIX);
Path userTrash = new Path(trashRoot, username);
Path current = new Path("Current");
Path userTrashCurrent = new Path(userTrash, current);

// Try to delete from trash path
args = new String[] {trashConfKey, "key", "delete",
"/volumefso1/bucket1/" + userTrashCurrent.toUri().getPath()
+ "/key4"};

out.reset();
execute(ozoneShell, args);

args = new String[] {"key", "list", "o3://" + omServiceId +
"/volumefso1/bucket1/", "-l ", "110"};
out.reset();
execute(ozoneShell, args);

// Total number of keys still remain 99 as
// delete from trash not allowed without --skipTrash
Assert.assertEquals(99, getNumOfKeys());

// Now try to delete from trash path with --skipTrash option
args = new String[] {trashConfKey, "key", "delete",
"/volumefso1/bucket1/" + userTrashCurrent.toUri().getPath()
+ "/key4", "--skipTrash"};
out.reset();
execute(ozoneShell, args);

args = new String[] {"key", "list", "o3://" + omServiceId +
"/volumefso1/bucket1/", "-l ", "110"};
out.reset();
execute(ozoneShell, args);

// Total number of keys now will be 98 as
// 1 key deleted without trash and 1 from the trash path
Assert.assertEquals(98, getNumOfKeys());
}

@Test
public void testKeyDeleteWhenTrashDisableFSO()
throws UnsupportedEncodingException {
// Create 100 keys
generateKeys("/volumefso2", "/bucket2",
BucketLayout.FILE_SYSTEM_OPTIMIZED.toString());
// Disable trash
String trashConfKey = generateSetConfString(
OMConfigKeys.OZONE_FS_TRASH_INTERVAL_KEY, "0");
String[] args =
new String[] {trashConfKey, "key",
"delete", "/volumefso2/bucket2/key4"};

execute(ozoneShell, args);

// Check in .Trash path number of keys
final String prefixKey = "--prefix=.Trash";
args = new String[] {"key", "list", prefixKey,
"o3://" + omServiceId + "/volumefso2/bucket2/"};
out.reset();
execute(ozoneShell, args);

// No key should be present in .Trash
Assert.assertEquals(0, getNumOfKeys());

args = new String[] {"key", "list", "o3://" +
omServiceId + "/volumefso2/bucket2/"};
out.reset();
execute(ozoneShell, args);

// Number of keys remain as 99
Assert.assertEquals(99, getNumOfKeys());
}

@Test
public void testKeyDeleteWhenTrashEnableOBS()
throws UnsupportedEncodingException {
generateKeys("/volumeobs1", "/bucket1",
BucketLayout.OBJECT_STORE.toString());

String trashConfKey = generateSetConfString(
OMConfigKeys.OZONE_FS_TRASH_INTERVAL_KEY, "1");
String[] args =
new String[] {trashConfKey, "key",
"delete", "/volumeobs1/bucket1/key4"};
execute(ozoneShell, args);

final String prefixKey = "--prefix=.Trash";
args = new String[] {"key", "list", prefixKey, "o3://" +
omServiceId + "/volumeobs1/bucket1/"};
out.reset();
execute(ozoneShell, args);
Assert.assertEquals(0, getNumOfKeys());

args = new String[] {"key", "list", "o3://" +
omServiceId + "/volumeobs1/bucket1/"};
out.reset();
execute(ozoneShell, args);

Assert.assertEquals(99, getNumOfKeys());
}


private void getVolume(String volumeName) {
String[] args = new String[] {"volume", "create",
"o3://" + omServiceId + "/" + volumeName};
Expand Down
Loading