Skip to content

Commit 39aeb20

Browse files
authored
HDDS-15100. Add an OM config to toggle Ozone snapshot rename feature (#10156)
1 parent fdd20f0 commit 39aeb20

9 files changed

Lines changed: 99 additions & 1 deletion

File tree

hadoop-hdds/common/src/main/resources/ozone-default.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3954,6 +3954,16 @@
39543954
</description>
39553955
</property>
39563956

3957+
<property>
3958+
<name>ozone.om.snapshot.rename.allowed</name>
3959+
<value>false</value>
3960+
<tag>OZONE, OM</tag>
3961+
<description>
3962+
Allows the Ozone snapshot rename operation if set to true on the OM side.
3963+
Blocks it otherwise.
3964+
</description>
3965+
</property>
3966+
39573967
<property>
39583968
<name>ozone.snapshot.deleting.service.timeout</name>
39593969
<value>300s</value>

hadoop-hdds/docs/content/feature/Snapshot-Configuration-Properties.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ These parameters, defined in `ozone-site.xml`, control how Ozone manages snapsho
3636
* `ozone.om.ratis.snapshot.max.total.sst.size`: The maximum total size of SST files to be included in a Ratis snapshot (Default: 10737418240).
3737
* `ozone.om.snapshot.load.native.lib`: Use native RocksDB library for snapshot operations (Default: true). Set to false as a workaround for native library issues.
3838
* `ozone.om.snapshot.checkpoint.dir.creation.poll.timeout`: Timeout for polling the creation of the snapshot checkpoint directory (Default: 20s).
39+
* `ozone.om.snapshot.rename.allowed`: Allow snapshot rename operation (Default: false).
3940

4041
* **SnapshotDiff Service**
4142
* `ozone.om.snapshot.diff.db.dir`: Directory for SnapshotDiff job data. Defaults to OM metadata dir. Use a spacious location for large diffs.

hadoop-hdds/docs/content/feature/Snapshot.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ Manage snapshots using `ozone sh` or `ozone fs` (Hadoop-compatible) commands:
135135
```shell
136136
ozone sh snapshot rename /vol1/bucket1 <oldName> <newName>
137137
```
138-
Requires bucket owner or admin.
138+
Requires `ozone.om.snapshot.rename.allowed=true` on the OM side and bucket owner or admin privileges.
139139

140140
* **Snapshot Info:**
141141
```shell

hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ public final class OMConfigKeys {
3030
public static final String OZONE_FILESYSTEM_SNAPSHOT_ENABLED_KEY =
3131
"ozone.filesystem.snapshot.enabled";
3232
public static final boolean OZONE_FILESYSTEM_SNAPSHOT_ENABLED_DEFAULT = true;
33+
public static final String OZONE_OM_SNAPSHOT_RENAME_ALLOWED_KEY =
34+
"ozone.om.snapshot.rename.allowed";
35+
public static final boolean OZONE_OM_SNAPSHOT_RENAME_ALLOWED_DEFAULT = false;
3336

3437
// Location where the OM stores its DB files. In the future we may support
3538
// multiple entries for performance (sharding)..

hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFsSnapshot.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,17 @@
2727
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_OFS_URI_SCHEME;
2828
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_SNAPSHOT_SST_FILTERING_SERVICE_INTERVAL;
2929
import static org.apache.hadoop.ozone.om.OmSnapshotManager.getSnapshotPath;
30+
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FEATURE_NOT_ENABLED;
3031
import static org.assertj.core.api.Assertions.assertThat;
3132
import static org.junit.jupiter.api.Assertions.assertEquals;
33+
import static org.junit.jupiter.api.Assertions.assertFalse;
3234
import static org.junit.jupiter.api.Assertions.assertNotNull;
35+
import static org.junit.jupiter.api.Assertions.assertThrows;
3336

3437
import java.io.ByteArrayOutputStream;
3538
import java.io.File;
3639
import java.io.IOException;
40+
import java.io.OutputStream;
3741
import java.io.PrintStream;
3842
import java.nio.charset.StandardCharsets;
3943
import java.nio.file.Files;
@@ -45,12 +49,16 @@
4549
import java.util.concurrent.atomic.AtomicInteger;
4650
import java.util.stream.Stream;
4751
import org.apache.commons.io.FileUtils;
52+
import org.apache.hadoop.hdds.cli.GenericCli;
4853
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
4954
import org.apache.hadoop.ozone.MiniOzoneCluster;
55+
import org.apache.hadoop.ozone.client.OzoneClient;
5056
import org.apache.hadoop.ozone.om.OMConfigKeys;
5157
import org.apache.hadoop.ozone.om.OmConfig;
5258
import org.apache.hadoop.ozone.om.OzoneManager;
59+
import org.apache.hadoop.ozone.om.exceptions.OMException;
5360
import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
61+
import org.apache.hadoop.ozone.shell.OzoneShell;
5462
import org.apache.hadoop.util.ToolRunner;
5563
import org.apache.ozone.test.GenericTestUtils;
5664
import org.junit.jupiter.api.AfterAll;
@@ -68,6 +76,9 @@
6876
*/
6977
class TestOzoneFsSnapshot {
7078

79+
private static final String SNAPSHOT_RENAME_NOT_ALLOWED_MESSAGE =
80+
"Ozone snapshot rename feature is not allowed per Ozone Manager server config";
81+
7182
private static MiniOzoneCluster cluster;
7283
private static final String OM_SERVICE_ID = "om-service-test1";
7384
private static OzoneManager ozoneManager;
@@ -95,6 +106,8 @@ static void initClass() throws Exception {
95106
conf.setInt(OZONE_SNAPSHOT_SST_FILTERING_SERVICE_INTERVAL, -1);
96107
conf.setInt(OmConfig.Keys.SERVER_LIST_MAX_SIZE, 20);
97108
conf.setInt(OZONE_FS_LISTING_PAGE_SIZE, 30);
109+
// Explicitly disable snapshot rename for the test
110+
conf.setBoolean(OMConfigKeys.OZONE_OM_SNAPSHOT_RENAME_ALLOWED_KEY, false);
98111

99112
// Start the cluster
100113
cluster = MiniOzoneCluster.newHABuilder(conf)
@@ -212,6 +225,44 @@ void testCreateSnapshotSuccess(String snapshotName)
212225
assertNotNull(snapshotInfo);
213226
}
214227

228+
@Test
229+
void testSnapshotRenameBlockedWhenConfigDisallows(@TempDir Path tempDir)
230+
throws Exception {
231+
assertFalse(cluster.getConf().getBoolean(
232+
OMConfigKeys.OZONE_OM_SNAPSHOT_RENAME_ALLOWED_KEY,
233+
OMConfigKeys.OZONE_OM_SNAPSHOT_RENAME_ALLOWED_DEFAULT));
234+
235+
String oldSnapshotName = createSnapshot();
236+
String newSnapshotName = "snap-" + counter.incrementAndGet();
237+
238+
try (OzoneClient ozoneClient = cluster.newClient()) {
239+
OMException omException = assertThrows(OMException.class,
240+
() -> ozoneClient.getObjectStore().renameSnapshot(
241+
VOLUME, BUCKET, oldSnapshotName, newSnapshotName));
242+
assertEquals(FEATURE_NOT_ENABLED, omException.getResult());
243+
assertEquals(SNAPSHOT_RENAME_NOT_ALLOWED_MESSAGE,
244+
omException.getMessage());
245+
}
246+
247+
Path confPath = tempDir.resolve("ozone-site.xml");
248+
try (OutputStream outputStream = Files.newOutputStream(confPath)) {
249+
cluster.getConf().writeXml(outputStream);
250+
}
251+
252+
try (GenericTestUtils.SystemErrCapturer capture =
253+
new GenericTestUtils.SystemErrCapturer()) {
254+
OzoneShell ozoneShell = new OzoneShell();
255+
int res = ozoneShell.execute(new String[] {
256+
"-conf", confPath.toString(), "snapshot", "rename",
257+
"o3://" + OM_SERVICE_ID + BUCKET_PATH,
258+
oldSnapshotName, newSnapshotName});
259+
260+
assertEquals(GenericCli.EXECUTION_ERROR_EXIT_CODE, res);
261+
assertThat(capture.getOutput()).contains(
262+
SNAPSHOT_RENAME_NOT_ALLOWED_MESSAGE);
263+
}
264+
}
265+
215266
private static Stream<Arguments> createSnapshotFailureScenarios() {
216267
String invalidBucketPath = "/invalid/uri";
217268
return Stream.of(

hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmMetrics.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ public void setup() throws Exception {
116116
conf.setTimeDuration(OMConfigKeys.OZONE_DIR_DELETING_SERVICE_INTERVAL, 1000, TimeUnit.MILLISECONDS);
117117
// For testing fs operations with legacy buckets.
118118
conf.setBoolean(OMConfigKeys.OZONE_OM_ENABLE_FILESYSTEM_PATHS, true);
119+
conf.setBoolean(OMConfigKeys.OZONE_OM_SNAPSHOT_RENAME_ALLOWED_KEY, true);
119120
clusterBuilder = MiniOzoneCluster.newBuilder(conf).setNumDatanodes(5);
120121
startCluster();
121122
}

hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestOzoneManagerSnapshotAcl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import org.apache.hadoop.ozone.client.VolumeArgs;
5252
import org.apache.hadoop.ozone.client.io.OzoneOutputStream;
5353
import org.apache.hadoop.ozone.om.KeyManagerImpl;
54+
import org.apache.hadoop.ozone.om.OMConfigKeys;
5455
import org.apache.hadoop.ozone.om.OMStorage;
5556
import org.apache.hadoop.ozone.om.OmSnapshotManager;
5657
import org.apache.hadoop.ozone.om.OzoneManager;
@@ -111,6 +112,7 @@ public static void init() throws Exception {
111112
conf.setBoolean(OZONE_TEST_AUTHORIZATION_ENABLED, true);
112113
conf.setBoolean(OZONE_ACL_ENABLED, true);
113114
conf.set(OZONE_ACL_AUTHORIZER_CLASS, OZONE_ACL_AUTHORIZER_CLASS_NATIVE);
115+
conf.setBoolean(OMConfigKeys.OZONE_OM_SNAPSHOT_RENAME_ALLOWED_KEY, true);
114116

115117
final String omServiceId = "om-service-test-1"
116118
+ RandomStringUtils.secure().nextNumeric(32);

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotRenameRequest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
package org.apache.hadoop.ozone.om.request.snapshot;
1919

20+
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_SNAPSHOT_RENAME_ALLOWED_DEFAULT;
21+
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_SNAPSHOT_RENAME_ALLOWED_KEY;
22+
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FEATURE_NOT_ENABLED;
2023
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FILE_ALREADY_EXISTS;
2124
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FILE_NOT_FOUND;
2225
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.LeveledResource.BUCKET_LOCK;
@@ -69,6 +72,13 @@ public OMSnapshotRenameRequest(OMRequest omRequest) {
6972
public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
7073
final OMRequest omRequest = super.preExecute(ozoneManager);
7174

75+
if (!ozoneManager.getConfiguration().getBoolean(
76+
OZONE_OM_SNAPSHOT_RENAME_ALLOWED_KEY,
77+
OZONE_OM_SNAPSHOT_RENAME_ALLOWED_DEFAULT)) {
78+
throw new OMException("Ozone snapshot rename feature is not allowed per Ozone Manager server config",
79+
FEATURE_NOT_ENABLED);
80+
}
81+
7282
final RenameSnapshotRequest renameSnapshotRequest =
7383
omRequest.getRenameSnapshotRequest();
7484

hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/snapshot/TestOMSnapshotRenameRequest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.apache.hadoop.ozone.om.request.snapshot;
1919

2020
import static org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor.THREE;
21+
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FEATURE_NOT_ENABLED;
2122
import static org.apache.hadoop.ozone.om.helpers.SnapshotInfo.SnapshotStatus.SNAPSHOT_ACTIVE;
2223
import static org.apache.hadoop.ozone.om.helpers.SnapshotInfo.getFromProtobuf;
2324
import static org.apache.hadoop.ozone.om.helpers.SnapshotInfo.getTableKey;
@@ -26,6 +27,7 @@
2627
import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status.OK;
2728
import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type.RenameSnapshot;
2829
import static org.junit.jupiter.api.Assertions.assertEquals;
30+
import static org.junit.jupiter.api.Assertions.assertFalse;
2931
import static org.junit.jupiter.api.Assertions.assertNotNull;
3032
import static org.junit.jupiter.api.Assertions.assertNull;
3133
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -38,6 +40,7 @@
3840
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
3941
import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
4042
import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
43+
import org.apache.hadoop.ozone.om.OMConfigKeys;
4144
import org.apache.hadoop.ozone.om.OzoneManager;
4245
import org.apache.hadoop.ozone.om.ResolvedBucket;
4346
import org.apache.hadoop.ozone.om.exceptions.OMException;
@@ -67,6 +70,8 @@ public class TestOMSnapshotRenameRequest extends TestSnapshotRequestAndResponse
6770
public void setup() throws Exception {
6871
snapshotName1 = UUID.randomUUID().toString();
6972
snapshotName2 = UUID.randomUUID().toString();
73+
getOzoneManager().getConfiguration().setBoolean(
74+
OMConfigKeys.OZONE_OM_SNAPSHOT_RENAME_ALLOWED_KEY, true);
7075
}
7176

7277
@ValueSource(strings = {
@@ -87,6 +92,21 @@ public void testPreExecute(String toSnapshotName) throws Exception {
8792
doPreExecute(omRequest);
8893
}
8994

95+
@Test
96+
public void testPreExecuteFailsWhenSnapshotRenameNotAllowed() {
97+
assertFalse(OMConfigKeys.OZONE_OM_SNAPSHOT_RENAME_ALLOWED_DEFAULT);
98+
getOzoneManager().getConfiguration().unset(
99+
OMConfigKeys.OZONE_OM_SNAPSHOT_RENAME_ALLOWED_KEY);
100+
101+
OzoneManagerProtocolProtos.OMRequest omRequest = renameSnapshotRequest(
102+
getVolumeName(), getBucketName(), snapshotName1, snapshotName2);
103+
OMException omException = assertThrows(OMException.class,
104+
() -> doPreExecute(omRequest));
105+
assertEquals(FEATURE_NOT_ENABLED, omException.getResult());
106+
assertEquals("Ozone snapshot rename feature is not allowed per Ozone Manager server config",
107+
omException.getMessage());
108+
}
109+
90110
@ValueSource(strings = {
91111
// '-' is allowed.
92112
"9cdf0e8a-6946-41ad-a2d1-9eb724fab126",

0 commit comments

Comments
 (0)