From 1b60b86012f9f5520cbc6a69f1fcd8b63b2abd97 Mon Sep 17 00:00:00 2001 From: Pedro Gordo Date: Sat, 4 Apr 2026 15:20:53 +0100 Subject: [PATCH] Update Config when properties are changed via JMX For snitch/dynamic_snitch, update Config fields so the Settings Virtual Table reflects the runtime state. For FQL and audit logging, resolve values directly from FullQueryLogger and AuditLogManager runtime instances, which revert to yaml defaults when disabled. Patch by Pedro Gordo; reviewed by Stefan Miklosovic, Marcus Eriksson for CASSANDRA-17736 --- .../cassandra/config/DatabaseDescriptor.java | 15 +++++ .../cassandra/db/virtual/SettingsTable.java | 55 +++++++++++++++---- .../cassandra/service/StorageService.java | 4 ++ .../service/StorageServiceServerTest.java | 13 +++++ 4 files changed, 77 insertions(+), 10 deletions(-) diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java index f102c3f729..0c8879bc22 100644 --- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java +++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java @@ -3201,6 +3201,21 @@ public class DatabaseDescriptor conf.dynamic_snitch_badness_threshold = dynamicBadnessThreshold; } + public static boolean isDynamicSnitch() + { + return conf.dynamic_snitch; + } + + public static void setDynamicSnitch(boolean enabled) + { + conf.dynamic_snitch = enabled; + } + + public static void setEndpointSnitchClassName(String endpointSnitch) + { + conf.endpoint_snitch = endpointSnitch; + } + public static EncryptionOptions.ServerEncryptionOptions getInternodeMessagingEncyptionOptions() { return conf.server_encryption_options; diff --git a/src/java/org/apache/cassandra/db/virtual/SettingsTable.java b/src/java/org/apache/cassandra/db/virtual/SettingsTable.java index c4e7d95698..54eeea175e 100644 --- a/src/java/org/apache/cassandra/db/virtual/SettingsTable.java +++ b/src/java/org/apache/cassandra/db/virtual/SettingsTable.java @@ -25,6 +25,8 @@ import java.util.Objects; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; +import org.apache.cassandra.audit.AuditLogManager; +import org.apache.cassandra.audit.AuditLogOptions; import org.apache.cassandra.config.Config; import org.apache.cassandra.config.Redacted; import org.apache.cassandra.config.DatabaseDescriptor; @@ -35,6 +37,8 @@ import org.apache.cassandra.config.Replacements; import org.apache.cassandra.db.DecoratedKey; import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.dht.LocalPartitioner; +import org.apache.cassandra.fql.FullQueryLogger; +import org.apache.cassandra.fql.FullQueryLoggerOptions; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.service.ClientWarn; import org.yaml.snakeyaml.introspector.Property; @@ -43,6 +47,12 @@ final class SettingsTable extends AbstractVirtualTable { private static final String NAME = "name"; private static final String VALUE = "value"; + private static final String FQL_PREFIX = "full_query_logging_options"; + private static final String AUDIT_PREFIX = "audit_logging_options"; + private static final Map FQL_PROPERTIES = ImmutableMap.copyOf( + Properties.defaultLoader().flatten(FullQueryLoggerOptions.class)); + private static final Map AUDIT_PROPERTIES = ImmutableMap.copyOf( + Properties.defaultLoader().flatten(AuditLogOptions.class)); private static final Map BACKWARDS_COMPATABLE_NAMES = ImmutableMap.copyOf(getBackwardsCompatableNames()); protected static final Map PROPERTIES = ImmutableMap.copyOf(getProperties()); @@ -87,6 +97,31 @@ final class SettingsTable extends AbstractVirtualTable return result; } + /** + * Returns the value to use for the given property. For FQL and audit logging properties, + * resolves from the current runtime options (which revert to yaml defaults when disabled) + * so the virtual table reflects the actual active state rather than the Config object. + */ + private Object resolveValue(Property prop) + { + String name = prop.getName(); + if (name.startsWith(FQL_PREFIX + ".")) + { + String subName = name.substring(FQL_PREFIX.length() + 1); + Property subProp = FQL_PROPERTIES.get(subName); + if (subProp != null) + return subProp.get(FullQueryLogger.instance.getFullQueryLoggerOptions()); + } + if (name.startsWith(AUDIT_PREFIX + ".")) + { + String subName = name.substring(AUDIT_PREFIX.length() + 1); + Property subProp = AUDIT_PROPERTIES.get(subName); + if (subProp != null) + return subProp.get(AuditLogManager.instance.getAuditLogOptions()); + } + return prop.get(config); + } + @VisibleForTesting String getValue(Property prop) { @@ -94,7 +129,7 @@ final class SettingsTable extends AbstractVirtualTable if (maybeCredential != null) return maybeCredential.redactedValue(); - Object value = prop.get(config); + Object value = resolveValue(prop); if (value == null) return null; @@ -162,21 +197,21 @@ final class SettingsTable extends AbstractVirtualTable { Map names = new HashMap<>(); // Names that dont match yaml - names.put("audit_logging_options_logger", "audit_logging_options.logger.class_name"); + names.put(AUDIT_PREFIX + "_logger", AUDIT_PREFIX + ".logger.class_name"); names.put("server_encryption_options_client_auth", "server_encryption_options.require_client_auth"); names.put("server_encryption_options_endpoint_verification", "server_encryption_options.require_endpoint_verification"); names.put("server_encryption_options_legacy_ssl_storage_port", "server_encryption_options.legacy_ssl_storage_port_enabled"); names.put("server_encryption_options_protocol", "server_encryption_options.accepted_protocols"); // matching names - names.put("audit_logging_options_audit_logs_dir", "audit_logging_options.audit_logs_dir"); - names.put("audit_logging_options_enabled", "audit_logging_options.enabled"); - names.put("audit_logging_options_excluded_categories", "audit_logging_options.excluded_categories"); - names.put("audit_logging_options_excluded_keyspaces", "audit_logging_options.excluded_keyspaces"); - names.put("audit_logging_options_excluded_users", "audit_logging_options.excluded_users"); - names.put("audit_logging_options_included_categories", "audit_logging_options.included_categories"); - names.put("audit_logging_options_included_keyspaces", "audit_logging_options.included_keyspaces"); - names.put("audit_logging_options_included_users", "audit_logging_options.included_users"); + names.put(AUDIT_PREFIX + "_audit_logs_dir", AUDIT_PREFIX + ".audit_logs_dir"); + names.put(AUDIT_PREFIX + "_enabled", AUDIT_PREFIX + ".enabled"); + names.put(AUDIT_PREFIX + "_excluded_categories", AUDIT_PREFIX + ".excluded_categories"); + names.put(AUDIT_PREFIX + "_excluded_keyspaces", AUDIT_PREFIX + ".excluded_keyspaces"); + names.put(AUDIT_PREFIX + "_excluded_users", AUDIT_PREFIX + ".excluded_users"); + names.put(AUDIT_PREFIX + "_included_categories", AUDIT_PREFIX + ".included_categories"); + names.put(AUDIT_PREFIX + "_included_keyspaces", AUDIT_PREFIX + ".included_keyspaces"); + names.put(AUDIT_PREFIX + "_included_users", AUDIT_PREFIX + ".included_users"); names.put("server_encryption_options_algorithm", "server_encryption_options.algorithm"); names.put("server_encryption_options_cipher_suites", "server_encryption_options.cipher_suites"); names.put("server_encryption_options_enabled", "server_encryption_options.enabled"); diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java index 8d494fc4d6..df76b18f1f 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -5963,10 +5963,14 @@ public class StorageService extends NotificationBroadcasterSupport implements IE // point snitch references to the new instance DatabaseDescriptor.setEndpointSnitch(newSnitch); + DatabaseDescriptor.setEndpointSnitchClassName(epSnitchClassName); for (String ks : Schema.instance.getKeyspaces()) { Keyspace.open(ks).getReplicationStrategy().snitch = newSnitch; } + + if (dynamic != null) + DatabaseDescriptor.setDynamicSnitch(dynamic); } else { diff --git a/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java b/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java index 119b8104d4..d146ad7b38 100644 --- a/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java +++ b/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java @@ -659,4 +659,17 @@ public class StorageServiceServerTest System.clearProperty("cassandra.replace_address"); } } + + @Test + public void testSnitchSettersUpdateConfig() + { + DatabaseDescriptor.setDynamicSnitch(false); + Assert.assertFalse(DatabaseDescriptor.isDynamicSnitch()); + DatabaseDescriptor.setDynamicSnitch(true); + Assert.assertTrue(DatabaseDescriptor.isDynamicSnitch()); + + DatabaseDescriptor.setEndpointSnitchClassName("org.apache.cassandra.locator.SimpleSnitch"); + Assert.assertEquals("org.apache.cassandra.locator.SimpleSnitch", + DatabaseDescriptor.getRawConfig().endpoint_snitch); + } } \ No newline at end of file