Add guardrail to disallow creation of secondary indexes

Patch by Josh McKenzie; reviewed by Chris Lohfink for CASSANDRA-17498
This commit is contained in:
Josh McKenzie 2022-03-29 14:18:10 -04:00
parent 105d69fdc5
commit 910bbb9b5f
9 changed files with 140 additions and 0 deletions

View File

@ -1,4 +1,5 @@
4.1
* Add guardrail for creation of secondary indexes (CASSANDRA-17498)
* Add guardrail to disallow creation of uncompressed tables (CASSANDRA-17504)
* Add guardrail to disallow creation of new COMPACT STORAGE tables (CASSANDRA-17522)
* repair vtables should expose a completed field due to lack of filtering options in CQL (CASSANDRA-17520)

View File

@ -1619,6 +1619,8 @@ drop_compact_storage_enabled: false
# The two thresholds default to -1 to disable.
# secondary_indexes_per_table_warn_threshold: -1
# secondary_indexes_per_table_fail_threshold: -1
# Guardrail to enable or disable the creation of secondary indexes
# secondary_indexes_enabled: true
# Guardrail to warn or fail when creating more materialized views per table than threshold.
# The two thresholds default to -1 to disable.
# materialized_views_per_table_warn_threshold: -1

View File

@ -800,6 +800,7 @@ public class Config
public volatile Set<ConsistencyLevel> write_consistency_levels_warned = Collections.emptySet();
public volatile Set<ConsistencyLevel> write_consistency_levels_disallowed = Collections.emptySet();
public volatile boolean user_timestamps_enabled = true;
public volatile boolean secondary_indexes_enabled = true;
public volatile boolean uncompressed_tables_enabled = true;
public volatile boolean compact_tables_enabled = true;
public volatile boolean read_before_write_list_operations_enabled = true;

View File

@ -332,6 +332,20 @@ public class GuardrailsOptions implements GuardrailsConfig
x -> config.user_timestamps_enabled = x);
}
@Override
public boolean getSecondaryIndexesEnabled()
{
return config.secondary_indexes_enabled;
}
public void setSecondaryIndexesEnabled(boolean enabled)
{
updatePropertyWithLogging("secondary_indexes_enabled",
enabled,
() -> config.secondary_indexes_enabled,
x -> config.secondary_indexes_enabled = x);
}
@Override
public boolean getUncompressedTablesEnabled()
{

View File

@ -84,6 +84,8 @@ public final class CreateIndexStatement extends AlterSchemaStatement
{
attrs.validate();
Guardrails.createSecondaryIndexesEnabled.ensureEnabled("Creating secondary indexes", state);
if (attrs.isCustom && attrs.customClass.equals(SASIIndex.class.getName()) && !DatabaseDescriptor.getSASIIndexesEnabled())
throw new InvalidRequestException("SASI indexes are disabled. Enable in cassandra.yaml to use.");

View File

@ -98,6 +98,14 @@ public final class Guardrails implements GuardrailsMBean
: format("Tables cannot have more than %s secondary indexes, aborting the creation of secondary index %s",
threshold, what));
/**
* Guardrail disabling user's ability to create secondary indexes
*/
public static final DisableFlag createSecondaryIndexesEnabled =
new DisableFlag("secondary_indexes",
state -> !CONFIG_PROVIDER.getOrCreate(state).getSecondaryIndexesEnabled(),
"User creation of secondary indexes");
/**
* Guardrail on the number of materialized views per table.
*/
@ -355,6 +363,18 @@ public final class Guardrails implements GuardrailsMBean
DEFAULT_CONFIG.setSecondaryIndexesPerTableThreshold(warn, fail);
}
@Override
public boolean getSecondaryIndexesEnabled()
{
return DEFAULT_CONFIG.getSecondaryIndexesEnabled();
}
@Override
public void setSecondaryIndexesEnabled(boolean enabled)
{
DEFAULT_CONFIG.setSecondaryIndexesEnabled(enabled);
}
@Override
public int getMaterializedViewsPerTableWarnThreshold()
{

View File

@ -93,6 +93,11 @@ public interface GuardrailsConfig
*/
int getSecondaryIndexesPerTableFailThreshold();
/**
* @return Whether creation of secondary indexes is allowed.
*/
boolean getSecondaryIndexesEnabled();
/**
* @return The threshold to warn when creating more materialized views per table than threshold.
*/

View File

@ -119,6 +119,17 @@ public interface GuardrailsMBean
*/
void setSecondaryIndexesPerTableThreshold(int warn, int fail);
/**
* @return Whether secondary index creation is active or not on the node
*/
boolean getSecondaryIndexesEnabled();
/**
* Enables or disables the ability to create secondary indexes
* @param enabled
*/
void setSecondaryIndexesEnabled(boolean enabled);
/**
* @return The threshold to warn when creating more materialized views per table than threshold.
* -1 means disabled.

View File

@ -0,0 +1,84 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.db.guardrails;
import org.junit.Before;
import org.junit.Test;
import static java.lang.String.format;
/**
* Tests the guardrail for disabling user creation of secondary indexes, {@link Guardrails#setSecondaryIndexesEnabled(boolean)}.
*/
public class GuardrailSecondaryIndexTester extends GuardrailTester
{
public GuardrailSecondaryIndexTester()
{
super(Guardrails.createSecondaryIndexesEnabled);
}
@Before
public void setupTest()
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, v1 int, v2 int, v3 int, v4 int)");
}
private void setGuardrail(boolean enabled)
{
guardrails().setSecondaryIndexesEnabled(enabled);
}
@Test
public void testCreateIndex() throws Throwable
{
setGuardrail(true);
assertValid(String.format("CREATE INDEX %s ON %s.%s(%s)", "v1_idx", keyspace(), currentTable(), "v1"));
assertValid(String.format("CREATE INDEX %s ON %s.%s(%s)", "v2_idx", keyspace(), currentTable(), "v2"));
setGuardrail(false);
assertFails(String.format("CREATE INDEX %s ON %s.%s(%s)", "v3_idx", keyspace(), currentTable(), "v3"), "Creating secondary indexes");
assertFails(String.format("CREATE INDEX %s ON %s.%s(%s)", "v4_idx", keyspace(), currentTable(), "v4"), "Creating secondary indexes");
assertFails(String.format("CREATE INDEX %s ON %s.%s(%s)", "v2_idx", keyspace(), currentTable(), "v2"), "Creating secondary indexes");
setGuardrail(true);
assertValid(String.format("CREATE INDEX %s ON %s.%s(%s)", "v3_idx", keyspace(), currentTable(), "v3"));
assertValid(String.format("CREATE INDEX %s ON %s.%s(%s)", "v4_idx", keyspace(), currentTable(), "v4"));
// Confirm can drop in either state
setGuardrail(false);
dropIndex(format("DROP INDEX %s.%s", keyspace(), "v1_idx"));
setGuardrail(true);
dropIndex(format("DROP INDEX %s.%s", keyspace(), "v2_idx"));
}
@Test
public void testCustomIndex() throws Throwable
{
// 2i guardrail will also affect custom indexes
setGuardrail(false);
assertFails(format("CREATE CUSTOM INDEX ON %%s (%s) USING 'org.apache.cassandra.index.sasi.SASIIndex'", "v4"),
format("Creating secondary indexes", currentTable())
);
// Confirm custom creation will work on flip
setGuardrail(true);
assertValid(format("CREATE CUSTOM INDEX ON %%s (%s) USING 'org.apache.cassandra.index.sasi.SASIIndex'", "v4"));
}
}