Merge branch 'cassandra-4.1' into trunk

This commit is contained in:
Marcus Eriksson 2023-05-25 08:43:27 +02:00
commit f36fd33e33
9 changed files with 83 additions and 3 deletions

View File

@ -149,6 +149,7 @@ Merged from 4.0:
* Fix COPY ... TO STDOUT behavior in cqlsh (CASSANDRA-18353)
* Remove six and Py2SaferScanner merge cruft (CASSANDRA-18354)
Merged from 4.0:
* Improve nodetool enable{audit,fullquery}log (CASSANDRA-18550)
* Report network cache info in nodetool (CASSANDRa-18400)
* Partial compaction can resurrect deleted data (CASSANDRA-18507)
* Allow internal address to change with reconnecting snitches (CASSANDRA-16718)

View File

@ -1623,6 +1623,8 @@ audit_logging_options:
# max_log_size: 17179869184 # 16 GiB
## archive command is "/path/to/script.sh %path" where %path is replaced with the file being rolled:
# archive_command:
## note that enabling this allows anyone with JMX/nodetool access to run local shell commands as the user running cassandra
# allow_nodetool_archive_command: false
# max_archive_retries: 10
# validate tombstones on reads and compaction

View File

@ -3940,6 +3940,11 @@ public class DatabaseDescriptor
return conf.full_query_logging_options;
}
public static void setFullQueryLogOptions(FullQueryLoggerOptions options)
{
conf.full_query_logging_options = options;
}
public static boolean getBlockForPeersInRemoteDatacenters()
{
return conf.block_for_peers_in_remote_dcs;

View File

@ -6732,7 +6732,11 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
String includedUsers, String excludedUsers, Integer maxArchiveRetries, Boolean block, String rollCycle,
Long maxLogSize, Integer maxQueueWeight, String archiveCommand) throws IllegalStateException
{
final AuditLogOptions options = new AuditLogOptions.Builder(DatabaseDescriptor.getAuditLoggingOptions())
AuditLogOptions auditOptions = DatabaseDescriptor.getAuditLoggingOptions();
if (archiveCommand != null && !auditOptions.allow_nodetool_archive_command)
throw new ConfigurationException("Can't enable audit log archiving via nodetool unless audit_logging_options.allow_nodetool_archive_command is set to true");
final AuditLogOptions options = new AuditLogOptions.Builder(auditOptions)
.withEnabled(true)
.withLogger(loggerName, parameters)
.withIncludedKeyspaces(includedKeyspaces)
@ -6835,6 +6839,8 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
blocking = blocking != null ? blocking : fqlOptions.block;
maxQueueWeight = maxQueueWeight != Integer.MIN_VALUE ? maxQueueWeight : fqlOptions.max_queue_weight;
maxLogSize = maxLogSize != Long.MIN_VALUE ? maxLogSize : fqlOptions.max_log_size;
if (archiveCommand != null && !fqlOptions.allow_nodetool_archive_command)
throw new ConfigurationException("Can't enable full query log archiving via nodetool unless full_query_logging_options.allow_nodetool_archive_command is set to true");
archiveCommand = archiveCommand != null ? archiveCommand : fqlOptions.archive_command;
maxArchiveRetries = maxArchiveRetries != Integer.MIN_VALUE ? maxArchiveRetries : fqlOptions.max_archive_retries;

View File

@ -62,7 +62,9 @@ public class EnableAuditLog extends NodeToolCmd
private long maxLogSize = Long.MIN_VALUE;
@Option(title = "archive_command", name = {"--archive-command"}, description = "Command that will handle archiving rolled audit log files." +
" Format is \"/path/to/script.sh %path\" where %path will be replaced with the file to archive")
" Format is \"/path/to/script.sh %path\" where %path will be replaced with the file to archive" +
" Enable this by setting the audit_logging_options.allow_nodetool_archive_command: true in the config.")
private String archiveCommand = null;
@Option(title = "archive_retries", name = {"--max-archive-retries"}, description = "Max number of archive retries.")

View File

@ -42,7 +42,8 @@ public class EnableFullQueryLog extends NodeToolCmd
private String path = null;
@Option(title = "archive_command", name = {"--archive-command"}, description = "Command that will handle archiving rolled full query log files." +
" Format is \"/path/to/script.sh %path\" where %path will be replaced with the file to archive")
" Format is \"/path/to/script.sh %path\" where %path will be replaced with the file to archive" +
" Enable this by setting the full_query_logging_options.allow_nodetool_archive_command: true in the config.")
private String archiveCommand = null;
@Option(title = "archive_retries", name = {"--max-archive-retries"}, description = "Max number of archive retries.")

View File

@ -23,6 +23,13 @@ import org.apache.commons.lang3.StringUtils;
public class BinLogOptions
{
public String archive_command = StringUtils.EMPTY;
/**
* enable if a user should be able to set the archive command via nodetool/jmx
*
* do not make this a hotprop.
*/
public boolean allow_nodetool_archive_command = false;
/**
* How often to roll BinLog segments so they can potentially be reclaimed. Available options are:
* MINUTELY, HOURLY, DAILY, LARGE_DAILY, XLARGE_DAILY, HUGE_DAILY.

View File

@ -21,6 +21,7 @@ import org.junit.After;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import org.junit.Assert;
import org.junit.Before;
@ -716,6 +717,34 @@ public class AuditLoggerTest extends CQLTester
assertEquals(0, AuthEvents.instance.listenerCount());
}
@Test
public void testJMXArchiveCommand()
{
disableAuditLogOptions();
AuditLogOptions options = new AuditLogOptions();
try
{
StorageService.instance.enableAuditLog("BinAuditLogger", Collections.emptyMap(), "", "", "", "",
"", "", 10, true, options.roll_cycle,
1000L, 1000, "/xyz/not/null");
fail("not allowed");
}
catch (ConfigurationException e)
{
assertTrue(e.getMessage().contains("Can't enable audit log archiving via nodetool"));
}
options.archive_command = "/xyz/not/null";
options.audit_logs_dir = "/tmp/abc";
DatabaseDescriptor.setAuditLoggingOptions(options);
StorageService.instance.enableAuditLog("BinAuditLogger", Collections.emptyMap(), "", "", "", "",
"", "", 10, true, options.roll_cycle,
1000L, 1000, null);
assertTrue(AuditLogManager.instance.isEnabled());
assertEquals("/xyz/not/null", AuditLogManager.instance.getAuditLogOptions().archive_command);
}
/**
* Helper methods for Audit Log CQL Testing
*/

View File

@ -43,15 +43,18 @@ import net.openhft.chronicle.queue.RollCycles;
import net.openhft.chronicle.wire.ValueIn;
import net.openhft.chronicle.wire.WireOut;
import org.apache.cassandra.Util;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQLTester;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.statements.BatchStatement;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.fql.FullQueryLogger.Query;
import org.apache.cassandra.fql.FullQueryLogger.Batch;
import org.apache.cassandra.cql3.statements.BatchStatement.Type;
import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.service.QueryState;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ObjectSizes;
import org.apache.cassandra.utils.binlog.BinLogTest;
@ -73,6 +76,7 @@ import static org.apache.cassandra.fql.FullQueryLogger.SINGLE_QUERY;
import static org.apache.cassandra.fql.FullQueryLogger.TYPE;
import static org.apache.cassandra.fql.FullQueryLogger.VALUES;
import static org.apache.cassandra.fql.FullQueryLogger.VERSION;
import static org.junit.Assert.fail;
public class FullQueryLoggerTest extends CQLTester
{
@ -669,6 +673,29 @@ public class FullQueryLoggerTest extends CQLTester
logQuery("", QueryOptions.DEFAULT, queryState(), -1);
}
@Test
public void testJMXArchiveCommand()
{
FullQueryLoggerOptions options = new FullQueryLoggerOptions();
try
{
StorageService.instance.enableFullQueryLogger(options.log_dir, options.roll_cycle, false, 1000, 1000, "/xyz/not/null", 0);
fail("not allowed");
}
catch (ConfigurationException e)
{
assertTrue(e.getMessage().contains("Can't enable full query log archiving via nodetool"));
}
options.archive_command = "/xyz/not/null";
options.log_dir = "/tmp/abc";
DatabaseDescriptor.setFullQueryLogOptions(options);
StorageService.instance.enableFullQueryLogger(options.log_dir, options.roll_cycle, false, 1000, 1000, null, 0);
assertTrue(FullQueryLogger.instance.isEnabled());
assertEquals("/xyz/not/null", FullQueryLogger.instance.getFullQueryLoggerOptions().archive_command);
}
private static void compareQueryOptions(QueryOptions a, QueryOptions b)
{
assertEquals(a.getClass(), b.getClass());