Skip to content

Commit b16ea44

Browse files
authored
HDDS-12791. Make Retention Service suspendable (apache#9426)
1 parent 724803f commit b16ea44

File tree

20 files changed

+720
-8
lines changed

20 files changed

+720
-8
lines changed

hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ public static boolean isReadOnly(
278278
case GetQuotaRepairStatus:
279279
case StartQuotaRepair:
280280
case GetLifecycleConfiguration:
281+
case GetLifecycleServiceStatus:
281282
return true;
282283
case CreateVolume:
283284
case SetVolumeProperty:
@@ -341,6 +342,7 @@ public static boolean isReadOnly(
341342
case DeleteObjectTagging:
342343
case SetLifecycleConfiguration:
343344
case DeleteLifecycleConfiguration:
345+
case SetLifecycleServiceStatus:
344346
case UnknownCommand:
345347
return false;
346348
case EchoRPC:

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
6767
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CancelPrepareResponse;
6868
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.EchoRPCResponse;
69+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetLifecycleServiceStatusResponse;
6970
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo;
7071
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PrepareStatusResponse;
7172
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PrepareStatusResponse.PrepareStatus;
@@ -1226,4 +1227,32 @@ default void deleteLifecycleConfiguration(String volumeName,
12261227
throw new UnsupportedOperationException("OzoneManager does not require " +
12271228
"this to be implemented, as write requests use a new approach.");
12281229
}
1230+
1231+
/**
1232+
* Gets the lifecycle service status.
1233+
* @return GetLifecycleServiceStatusResponse
1234+
* @throws IOException
1235+
*/
1236+
default GetLifecycleServiceStatusResponse getLifecycleServiceStatus() throws IOException {
1237+
throw new UnsupportedOperationException("OzoneManager does not require " +
1238+
"this to be implemented, as write requests use a new approach.");
1239+
}
1240+
1241+
/**
1242+
* Suspends the lifecycle service.
1243+
* @throws IOException
1244+
*/
1245+
default void suspendLifecycleService() throws IOException {
1246+
throw new UnsupportedOperationException("OzoneManager does not require " +
1247+
"this to be implemented, as write requests use a new approach.");
1248+
}
1249+
1250+
/**
1251+
* Resumes the lifecycle service.
1252+
* @throws IOException
1253+
*/
1254+
default void resumeLifecycleService() throws IOException {
1255+
throw new UnsupportedOperationException("OzoneManager does not require " +
1256+
"this to be implemented, as write requests use a new approach.");
1257+
}
12291258
}

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetKeyInfoResponse;
142142
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetLifecycleConfigurationRequest;
143143
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetLifecycleConfigurationResponse;
144+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetLifecycleServiceStatusResponse;
144145
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetObjectTaggingRequest;
145146
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetObjectTaggingResponse;
146147
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetS3SecretRequest;
@@ -2691,6 +2692,21 @@ public OmLifecycleConfiguration getLifecycleConfiguration(String volumeName,
26912692
resp.getLifecycleConfiguration());
26922693
}
26932694

2695+
@Override
2696+
public GetLifecycleServiceStatusResponse getLifecycleServiceStatus() throws IOException {
2697+
OzoneManagerProtocolProtos.GetLifecycleServiceStatusRequest
2698+
getLifecycleServiceStatusRequest =
2699+
OzoneManagerProtocolProtos.GetLifecycleServiceStatusRequest
2700+
.newBuilder().build();
2701+
2702+
OMRequest omRequest = createOMRequest(Type.GetLifecycleServiceStatus)
2703+
.setGetLifecycleServiceStatusRequest(getLifecycleServiceStatusRequest)
2704+
.build();
2705+
2706+
return handleError(submitRequest(omRequest))
2707+
.getGetLifecycleServiceStatusResponse();
2708+
}
2709+
26942710
@Override
26952711
public void setLifecycleConfiguration(
26962712
OmLifecycleConfiguration omLifecycleConfiguration) throws IOException {
@@ -2724,6 +2740,34 @@ public void deleteLifecycleConfiguration(String volumeName, String bucketName)
27242740
handleError(submitRequest(omRequest));
27252741
}
27262742

2743+
@Override
2744+
public void suspendLifecycleService() throws IOException {
2745+
OzoneManagerProtocolProtos.SetLifecycleServiceStatusRequest
2746+
setLifecycleServiceStatusRequest =
2747+
OzoneManagerProtocolProtos.SetLifecycleServiceStatusRequest
2748+
.newBuilder().setSuspend(true).build();
2749+
2750+
OMRequest omRequest = createOMRequest(Type.SetLifecycleServiceStatus)
2751+
.setSetLifecycleServiceStatusRequest(setLifecycleServiceStatusRequest)
2752+
.build();
2753+
2754+
handleError(submitRequest(omRequest));
2755+
}
2756+
2757+
@Override
2758+
public void resumeLifecycleService() throws IOException {
2759+
OzoneManagerProtocolProtos.SetLifecycleServiceStatusRequest
2760+
setLifecycleServiceStatusRequest =
2761+
OzoneManagerProtocolProtos.SetLifecycleServiceStatusRequest
2762+
.newBuilder().setSuspend(false).build();
2763+
2764+
OMRequest omRequest = createOMRequest(Type.SetLifecycleServiceStatus)
2765+
.setSetLifecycleServiceStatusRequest(setLifecycleServiceStatusRequest)
2766+
.build();
2767+
2768+
handleError(submitRequest(omRequest));
2769+
}
2770+
27272771
private SafeMode toProtoBuf(SafeModeAction action) {
27282772
switch (action) {
27292773
case ENTER:

hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneShellHA.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ protected static void startCluster(OzoneConfiguration conf) throws Exception {
194194
conf.setInt(OMConfigKeys.OZONE_DIR_DELETING_SERVICE_INTERVAL, 10);
195195
conf.setBoolean(OMConfigKeys.OZONE_OM_ENABLE_FILESYSTEM_PATHS, true);
196196
conf.setInt(ScmConfigKeys.OZONE_SCM_CONTAINER_LIST_MAX_COUNT, 1);
197+
conf.setBoolean(OMConfigKeys.OZONE_KEY_LIFECYCLE_SERVICE_ENABLED, true);
197198
ozoneConfiguration = conf;
198199
MiniOzoneHAClusterImpl.Builder builder = MiniOzoneCluster.newHABuilder(conf);
199200
builder.setOMServiceId(omServiceId)
@@ -1834,6 +1835,81 @@ public void testSetEncryptionKey() throws Exception {
18341835
assertEquals(newEncKey, volume.getBucket("bucket0").getEncryptionKeyName());
18351836
}
18361837

1838+
@Test
1839+
public void testLifecycleStatus() throws UnsupportedEncodingException {
1840+
String[] args = new String[] {"om", "lifecycle", "status", "--service-id", omServiceId};
1841+
execute(ozoneAdminShell, args);
1842+
String output = out.toString(DEFAULT_ENCODING);
1843+
assertThat(output).contains("IsEnabled:");
1844+
}
1845+
1846+
@Test
1847+
public void testLifecycleSuspendAndResume() throws Exception {
1848+
List<OzoneManager> ozoneManagers = cluster.getOzoneManagersList();
1849+
for (OzoneManager om : ozoneManagers) {
1850+
assertNotNull(om.getKeyManager().getKeyLifecycleService());
1851+
assertTrue(om.getLifecycleServiceStatus().getIsEnabled());
1852+
assertFalse(om.getLifecycleServiceStatus().getIsSuspended());
1853+
}
1854+
1855+
// Execute suspend command
1856+
String[] args = new String[] {"om", "lifecycle", "suspend", "--service-id", omServiceId};
1857+
execute(ozoneAdminShell, args);
1858+
String output = out.toString(DEFAULT_ENCODING);
1859+
assertThat(output).contains("Lifecycle Service has been suspended");
1860+
out.reset();
1861+
1862+
// Wait for the suspend command to propagate through Ratis to all OMs
1863+
GenericTestUtils.waitFor(() -> {
1864+
for (OzoneManager om : ozoneManagers) {
1865+
assertNotNull(om.getKeyManager().getKeyLifecycleService());
1866+
if (!om.getLifecycleServiceStatus().getIsSuspended()) {
1867+
return false;
1868+
}
1869+
}
1870+
return true;
1871+
}, 100, 10000);
1872+
1873+
// Verify lifecycle service is suspended on all OMs
1874+
for (OzoneManager om : ozoneManagers) {
1875+
if (om.getKeyManager().getKeyLifecycleService() != null) {
1876+
assertTrue(om.getLifecycleServiceStatus().getIsSuspended(),
1877+
"Lifecycle service should be suspended on OM: " + om.getOMNodeId());
1878+
// isEnabled should still be true (based on configuration)
1879+
assertTrue(om.getLifecycleServiceStatus().getIsEnabled(),
1880+
"Lifecycle service isEnabled should still be true on OM: " + om.getOMNodeId());
1881+
}
1882+
}
1883+
1884+
// Execute resume command
1885+
args = new String[] {"om", "lifecycle", "resume", "--service-id", omServiceId};
1886+
execute(ozoneAdminShell, args);
1887+
output = out.toString(DEFAULT_ENCODING);
1888+
assertThat(output).contains("Lifecycle Service has been resumed");
1889+
out.reset();
1890+
1891+
// Wait for the resume command to propagate through Ratis to all OMs
1892+
GenericTestUtils.waitFor(() -> {
1893+
for (OzoneManager om : ozoneManagers) {
1894+
assertNotNull(om.getKeyManager().getKeyLifecycleService());
1895+
if (om.getLifecycleServiceStatus().getIsSuspended()) {
1896+
return false;
1897+
}
1898+
}
1899+
return true;
1900+
}, 100, 10000);
1901+
1902+
// Verify lifecycle service is resumed on all OMs
1903+
for (OzoneManager om : ozoneManagers) {
1904+
if (om.getKeyManager().getKeyLifecycleService() != null) {
1905+
assertFalse(om.getLifecycleServiceStatus().getIsSuspended(),
1906+
"Lifecycle service should be resumed on OM: " + om.getOMNodeId());
1907+
assertTrue(om.getLifecycleServiceStatus().getIsEnabled(),
1908+
"Lifecycle service isEnabled should be true on OM: " + om.getOMNodeId());
1909+
}
1910+
}
1911+
}
1912+
18371913
@Test
18381914
public void testCreateBucketWithECReplicationConfigWithoutReplicationParam() {
18391915
getVolume("volume102");

hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ enum Type {
159159
SetLifecycleConfiguration = 150;
160160
GetLifecycleConfiguration = 151;
161161
DeleteLifecycleConfiguration = 152;
162+
GetLifecycleServiceStatus = 153;
163+
SetLifecycleServiceStatus = 154;
162164
}
163165

164166
enum SafeMode {
@@ -310,6 +312,9 @@ message OMRequest {
310312
optional SetLifecycleConfigurationRequest setLifecycleConfigurationRequest = 150;
311313
optional GetLifecycleConfigurationRequest getLifecycleConfigurationRequest = 151;
312314
optional DeleteLifecycleConfigurationRequest deleteLifecycleConfigurationRequest = 152;
315+
316+
optional GetLifecycleServiceStatusRequest getLifecycleServiceStatusRequest = 153;
317+
optional SetLifecycleServiceStatusRequest setLifecycleServiceStatusRequest = 154;
313318
}
314319

315320
message OMResponse {
@@ -447,6 +452,9 @@ message OMResponse {
447452
optional SetLifecycleConfigurationResponse setLifecycleConfigurationResponse = 150;
448453
optional GetLifecycleConfigurationResponse getLifecycleConfigurationResponse = 151;
449454
optional DeleteLifecycleConfigurationResponse deleteLifecycleConfigurationResponse = 152;
455+
456+
optional GetLifecycleServiceStatusResponse getLifecycleServiceStatusResponse = 153;
457+
optional SetLifecycleServiceStatusResponse setLifecycleServiceStatusResponse = 154;
450458
}
451459

452460
enum Status {
@@ -2439,3 +2447,20 @@ service OzoneManagerService {
24392447
rpc submitRequest(OMRequest)
24402448
returns(OMResponse);
24412449
}
2450+
2451+
message GetLifecycleServiceStatusRequest {
2452+
}
2453+
2454+
message GetLifecycleServiceStatusResponse {
2455+
required bool isEnabled = 1;
2456+
optional bool isSuspended = 2;
2457+
repeated string runningBuckets = 3;
2458+
}
2459+
2460+
message SetLifecycleServiceStatusRequest {
2461+
required bool suspend = 1;
2462+
}
2463+
2464+
message SetLifecycleServiceStatusResponse {
2465+
}
2466+

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ public enum OMAction implements AuditAction {
117117

118118
GET_LIFECYCLE_CONFIGURATION,
119119
SET_LIFECYCLE_CONFIGURATION,
120-
DELETE_LIFECYCLE_CONFIGURATION;
120+
DELETE_LIFECYCLE_CONFIGURATION,
121+
GET_LIFECYCLE_SERVICE_STATUS,
122+
SET_LIFECYCLE_SERVICE_STATUS;
121123

122124
@Override
123125
public String getAction() {

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_DEFAULT_BUCKET_LAYOUT;
5454
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_DEFAULT_BUCKET_LAYOUT_DEFAULT;
5555
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_KEY_DELETING_LIMIT_PER_TASK;
56+
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_KEY_LIFECYCLE_SERVICE_ENABLED;
57+
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_KEY_LIFECYCLE_SERVICE_ENABLED_DEFAULT;
5658
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_ADDRESS_KEY;
5759
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_EDEKCACHELOADER_INITIAL_DELAY_MS_DEFAULT;
5860
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_EDEKCACHELOADER_INITIAL_DELAY_MS_KEY;
@@ -283,6 +285,7 @@
283285
import org.apache.hadoop.ozone.om.s3.S3SecretCacheProvider;
284286
import org.apache.hadoop.ozone.om.s3.S3SecretStoreProvider;
285287
import org.apache.hadoop.ozone.om.service.CompactDBService;
288+
import org.apache.hadoop.ozone.om.service.KeyLifecycleService;
286289
import org.apache.hadoop.ozone.om.service.OMRangerBGSyncService;
287290
import org.apache.hadoop.ozone.om.service.QuotaRepairTask;
288291
import org.apache.hadoop.ozone.om.snapshot.OmSnapshotUtils;
@@ -295,6 +298,7 @@
295298
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DBUpdatesRequest;
296299
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.EchoRPCResponse;
297300
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ExtendedUserAccessIdInfo;
301+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetLifecycleServiceStatusResponse;
298302
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.KeyArgs;
299303
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRoleInfo;
300304
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.S3Authentication;
@@ -3159,6 +3163,18 @@ public OmLifecycleConfiguration getLifecycleConfiguration(String volumeName,
31593163
}
31603164
}
31613165

3166+
@Override
3167+
public GetLifecycleServiceStatusResponse getLifecycleServiceStatus() {
3168+
KeyLifecycleService keyLifecycleService = keyManager.getKeyLifecycleService();
3169+
if (keyLifecycleService == null) {
3170+
return GetLifecycleServiceStatusResponse.newBuilder()
3171+
.setIsEnabled(getConfiguration().getBoolean(OZONE_KEY_LIFECYCLE_SERVICE_ENABLED,
3172+
OZONE_KEY_LIFECYCLE_SERVICE_ENABLED_DEFAULT))
3173+
.build();
3174+
}
3175+
return keyLifecycleService.status();
3176+
}
3177+
31623178
private Map<String, String> buildAuditMap(String volume) {
31633179
Map<String, String> auditMap = new LinkedHashMap<>();
31643180
auditMap.put(OzoneConsts.VOLUME, volume);

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/helpers/OMAuditLogger.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ private static void init() {
9393
CMD_AUDIT_ACTION_MAP.put(Type.GetObjectTagging, OMAction.GET_OBJECT_TAGGING);
9494
CMD_AUDIT_ACTION_MAP.put(Type.PutObjectTagging, OMAction.PUT_OBJECT_TAGGING);
9595
CMD_AUDIT_ACTION_MAP.put(Type.DeleteObjectTagging, OMAction.DELETE_OBJECT_TAGGING);
96+
CMD_AUDIT_ACTION_MAP.put(Type.SetLifecycleServiceStatus, OMAction.SET_LIFECYCLE_SERVICE_STATUS);
9697
}
9798

9899
private static OMAction getAction(OzoneManagerProtocolProtos.OMRequest request) {

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import org.apache.hadoop.ozone.om.request.key.acl.prefix.OMPrefixSetAclRequest;
6969
import org.apache.hadoop.ozone.om.request.lifecycle.OMLifecycleConfigurationDeleteRequest;
7070
import org.apache.hadoop.ozone.om.request.lifecycle.OMLifecycleConfigurationSetRequest;
71+
import org.apache.hadoop.ozone.om.request.lifecycle.OMLifecycleSetServiceStatusRequest;
7172
import org.apache.hadoop.ozone.om.request.s3.multipart.S3ExpiredMultipartUploadsAbortRequest;
7273
import org.apache.hadoop.ozone.om.request.s3.security.OMSetSecretRequest;
7374
import org.apache.hadoop.ozone.om.request.s3.security.S3GetSecretRequest;
@@ -351,6 +352,8 @@ public static OMClientRequest createClientRequest(OMRequest omRequest,
351352
return new OMLifecycleConfigurationSetRequest(omRequest);
352353
case DeleteLifecycleConfiguration:
353354
return new OMLifecycleConfigurationDeleteRequest(omRequest);
355+
case SetLifecycleServiceStatus:
356+
return new OMLifecycleSetServiceStatusRequest(omRequest);
354357
default:
355358
throw new OMException("Unrecognized write command type request "
356359
+ cmdType, OMException.ResultCodes.INVALID_REQUEST);

0 commit comments

Comments
 (0)