Skip to content

Commit 3b80522

Browse files
feat(inkless:config): disallow setting diskless.enable if diskless storage system is disabled (#520)
1 parent b54cd40 commit 3b80522

3 files changed

Lines changed: 61 additions & 8 deletions

File tree

core/src/main/scala/kafka/server/ControllerConfigurationValidator.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ class ControllerConfigurationValidator(kafkaConfig: KafkaConfig) extends Configu
119119
}
120120
LogConfig.validate(oldConfigs, properties, kafkaConfig.extractLogConfigMap,
121121
kafkaConfig.remoteLogManagerConfig.isRemoteStorageSystemEnabled(),
122-
kafkaConfig.disklessAllowFromClassicEnabled)
122+
kafkaConfig.disklessAllowFromClassicEnabled,
123+
kafkaConfig.disklessStorageSystemEnabled)
123124
case BROKER => validateBrokerName(resource.name())
124125
case CLIENT_METRICS =>
125126
val properties = new Properties()

core/src/test/scala/unit/kafka/log/LogConfigTest.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test
2929
import java.util
3030
import java.util.Properties
3131
import org.apache.kafka.server.config.ServerLogConfigs
32+
import org.apache.kafka.server.config.ServerConfigs
3233
import org.apache.kafka.server.log.remote.storage.RemoteLogManagerConfig
3334
import org.apache.kafka.storage.internals.log.{LogConfig, ThrottledReplicaListValidator}
3435
import org.junit.jupiter.params.ParameterizedTest
@@ -471,6 +472,26 @@ class LogConfigTest {
471472
kafkaConfig)
472473
}
473474

475+
@ParameterizedTest(name = "testDisklessExplicitConfigRejectedWhenSystemDisabled with value: {0}")
476+
@ValueSource(booleans = Array(true, false))
477+
def testDisklessExplicitConfigRejectedWhenSystemDisabled(disklessEnableValue: Boolean): Unit = {
478+
val kafkaProps = TestUtils.createDummyBrokerConfig()
479+
kafkaProps.put(ServerConfigs.DISKLESS_STORAGE_SYSTEM_ENABLE_CONFIG, "false")
480+
val kafkaConfig = KafkaConfig.fromProps(kafkaProps)
481+
482+
val ex = assertThrows(classOf[InvalidConfigurationException],
483+
() => LogConfig.validate(
484+
util.Map.of[String, String](),
485+
topicProps(TopicConfig.DISKLESS_ENABLE_CONFIG -> disklessEnableValue.toString),
486+
kafkaConfig.extractLogConfigMap,
487+
kafkaConfig.remoteLogManagerConfig.isRemoteStorageSystemEnabled,
488+
kafkaConfig.disklessAllowFromClassicEnabled,
489+
kafkaConfig.disklessStorageSystemEnabled
490+
))
491+
assertEquals("It is invalid to set diskless.enable if diskless storage system is not enabled.",
492+
ex.getMessage)
493+
}
494+
474495
@Test
475496
def testDisklessAndRemoteStorageAtUpdate(): Unit = {
476497
val kafkaConfig = KafkaConfig.fromProps(TestUtils.createDummyBrokerConfig())

storage/src/main/java/org/apache/kafka/storage/internals/log/LogConfig.java

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,8 @@ public static void validateBrokerLogConfigValues(Map<?, ?> props,
497497

498498
private static void validateDiskless(Map<String, String> existingConfigs,
499499
Map<String, Object> requestedConfigs,
500-
Map<?, ?> newConfigs) {
500+
Map<?, ?> newConfigs,
501+
boolean isDisklessStorageSystemEnabled) {
501502
final boolean isCreation = existingConfigs.isEmpty();
502503
final boolean isDisklessExplicitlySet = requestedConfigs.containsKey(TopicConfig.DISKLESS_ENABLE_CONFIG);
503504
final boolean isRemoteStorageExplicitlySet = requestedConfigs.containsKey(TopicConfig.REMOTE_LOG_STORAGE_ENABLE_CONFIG);
@@ -506,13 +507,29 @@ private static void validateDiskless(Map<String, String> existingConfigs,
506507
final boolean wasDisklessEnabled = Boolean.parseBoolean(existingConfigs.getOrDefault(TopicConfig.DISKLESS_ENABLE_CONFIG, "false"));
507508
final boolean requestedDisklessEnabled = (Boolean) newConfigs.get(TopicConfig.DISKLESS_ENABLE_CONFIG);
508509

510+
if (isDisklessExplicitlySet && !isDisklessStorageSystemEnabled) {
511+
throw new InvalidConfigurationException("It is invalid to set diskless.enable if diskless storage system is not enabled.");
512+
}
513+
509514
final boolean isDisklessEnabled;
510515
if (isDisklessExplicitlySet) {
511516
isDisklessEnabled = requestedDisklessEnabled;
512517
} else {
513518
isDisklessEnabled = wasDisklessEnabled;
514519
}
515520

521+
validateDisklessTransition(isCreation, isDisklessExplicitlySet, isDisklessEnabled, wasDisklessEnabled);
522+
523+
// Only one between diskless.enable and remote.storage.enable can be set, no matter the value.
524+
final boolean hasExplicitDiskless = isDisklessExplicitlySet || wasDisklessExplicitlySet;
525+
final boolean hasExplicitRemoteStorage = isRemoteStorageExplicitlySet || wasRemoteStorageExplicitlySet;
526+
validateDisklessAndRemoteStorageMutualExclusion(isDisklessExplicitlySet, isRemoteStorageExplicitlySet, hasExplicitDiskless, hasExplicitRemoteStorage);
527+
}
528+
529+
private static void validateDisklessTransition(boolean isCreation,
530+
boolean isDisklessExplicitlySet,
531+
boolean isDisklessEnabled,
532+
boolean wasDisklessEnabled) {
516533
// Diskless can be enabled only at creation
517534
if (!isCreation && isDisklessExplicitlySet && isDisklessEnabled && !wasDisklessEnabled) {
518535
throw new InvalidConfigurationException("It is invalid to enable diskless on an already existing topic.");
@@ -522,10 +539,12 @@ private static void validateDiskless(Map<String, String> existingConfigs,
522539
if (!isCreation && isDisklessExplicitlySet && !isDisklessEnabled && wasDisklessEnabled) {
523540
throw new InvalidConfigurationException("It is invalid to disable diskless.");
524541
}
542+
}
525543

526-
// Only one between diskless.enable and remote.storage.enable can be set, no matter the value.
527-
final boolean hasExplicitDiskless = isDisklessExplicitlySet || wasDisklessExplicitlySet;
528-
final boolean hasExplicitRemoteStorage = isRemoteStorageExplicitlySet || wasRemoteStorageExplicitlySet;
544+
private static void validateDisklessAndRemoteStorageMutualExclusion(boolean isDisklessExplicitlySet,
545+
boolean isRemoteStorageExplicitlySet,
546+
boolean hasExplicitDiskless,
547+
boolean hasExplicitRemoteStorage) {
529548
if ((isDisklessExplicitlySet && hasExplicitRemoteStorage) ||
530549
(isRemoteStorageExplicitlySet && hasExplicitDiskless)) {
531550
throw new InvalidConfigurationException("It is not valid to set a value for both diskless.enable and remote.storage.enable.");
@@ -545,9 +564,10 @@ private static void validateDiskless(Map<String, String> existingConfigs,
545564
private static void validateTopicLogConfigValues(Map<String, String> existingConfigs,
546565
Map<String, Object> requestedConfigs,
547566
Map<?, ?> newConfigs,
548-
boolean isRemoteLogStorageSystemEnabled) {
567+
boolean isRemoteLogStorageSystemEnabled,
568+
boolean isDisklessStorageSystemEnabled) {
549569
validateValues(newConfigs);
550-
validateDiskless(existingConfigs, requestedConfigs, newConfigs);
570+
validateDiskless(existingConfigs, requestedConfigs, newConfigs, isDisklessStorageSystemEnabled);
551571

552572
boolean isRemoteLogStorageEnabled = (Boolean) newConfigs.get(TopicConfig.REMOTE_LOG_STORAGE_ENABLE_CONFIG);
553573
if (isRemoteLogStorageEnabled) {
@@ -663,6 +683,16 @@ public static void validate(Map<String, String> existingConfigs,
663683
Map<?, ?> configuredProps,
664684
boolean isRemoteLogStorageSystemEnabled,
665685
boolean isDisklessAllowFromClassicEnabled) {
686+
validate(existingConfigs, props, configuredProps, isRemoteLogStorageSystemEnabled,
687+
isDisklessAllowFromClassicEnabled, true);
688+
}
689+
690+
public static void validate(Map<String, String> existingConfigs,
691+
Properties props,
692+
Map<?, ?> configuredProps,
693+
boolean isRemoteLogStorageSystemEnabled,
694+
boolean isDisklessAllowFromClassicEnabled,
695+
boolean isDisklessStorageSystemEnabled) {
666696
validateNames(props);
667697
if (configuredProps == null || configuredProps.isEmpty()) {
668698
Map<?, ?> valueMaps = CONFIG.parse(props);
@@ -671,7 +701,8 @@ public static void validate(Map<String, String> existingConfigs,
671701
Map<Object, Object> combinedConfigs = new HashMap<>(configuredProps);
672702
combinedConfigs.putAll(props);
673703
Map<?, ?> valueMaps = CONFIG.parse(combinedConfigs);
674-
validateTopicLogConfigValues(existingConfigs, Utils.castToStringObjectMap(props), valueMaps, isRemoteLogStorageSystemEnabled);
704+
validateTopicLogConfigValues(existingConfigs, Utils.castToStringObjectMap(props), valueMaps,
705+
isRemoteLogStorageSystemEnabled, isDisklessStorageSystemEnabled);
675706
}
676707
}
677708

0 commit comments

Comments
 (0)