Skip to content
Permalink
Browse files
Rename DisableFlag class to EnableFlag on guardrails
patch by Bernardo Botella Corbi; reviewed by Andrés de la Peña, Josh McKenzie and Yifan Cai for CASSANDRA-17544
  • Loading branch information
bbotella authored and adelapena committed May 6, 2022
1 parent c489063 commit 013acc641c5d487b07be5c082af1e85d26bd127f
Showing 5 changed files with 135 additions and 134 deletions.
@@ -1,4 +1,5 @@
4.2
* Rename DisableFlag class to EnableFlag on guardrails (CASSANDRA-17544)
Merged from 4.1:
Merged from 4.0:
Merged from 3.11:

This file was deleted.

@@ -0,0 +1,86 @@
/*
* 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 java.util.function.Predicate;
import javax.annotation.Nullable;

import org.apache.cassandra.service.ClientState;

/**
* A guardrail that enables the use of a particular feature.
*
* <p>Note that this guardrail only aborts operations (if the feature is not enabled) so is only meant for query-based
* guardrails (we're happy to reject queries deemed dangerous, but we don't want to create a guardrail that breaks
* compaction for instance).
*/
public class EnableFlag extends Guardrail
{
private final Predicate<ClientState> enabled;
private final String featureName;

/**
* Creates a new {@link EnableFlag} guardrail.
*
* @param name the identifying name of the guardrail
* @param enabled a {@link ClientState}-based supplier of boolean indicating whether the feature guarded by this
* guardrail is enabled.
* @param featureName The feature that is guarded by this guardrail (for reporting in error messages), {@link
* EnableFlag#ensureEnabled(String, ClientState)} can specify a different {@code featureName}.
*/
public EnableFlag(String name, Predicate<ClientState> enabled, String featureName)
{
super(name);
this.enabled = enabled;
this.featureName = featureName;
}

/**
* Aborts the operation if this guardrail is not enabled.
*
* <p>This must be called when the feature guarded by this guardrail is used to ensure such use is in fact
* allowed.
*
* @param state The client state, used to skip the check if the query is internal or is done by a superuser.
* A {@code null} value means that the check should be done regardless of the query.
*/
public void ensureEnabled(@Nullable ClientState state)
{
ensureEnabled(featureName, state);
}

/**
* Aborts the operation if this guardrail is not enabled.
*
* <p>This must be called when the feature guarded by this guardrail is used to ensure such use is in fact
* allowed.
*
* @param featureName The feature that is guarded by this guardrail (for reporting in error messages).
* @param state The client state, used to skip the check if the query is internal or is done by a superuser. A
* {@code null} value means that the check should be done regardless of the query, although it
* won't throw any exception if the failure threshold is exceeded. This is so because checks
* without an associated client come from asynchronous processes such as compaction, and we don't
* want to interrupt such processes.
*/
public void ensureEnabled(String featureName, @Nullable ClientState state)
{
if (enabled(state) && !enabled.test(state))
fail(featureName + " is not allowed", state);
}
}
@@ -104,10 +104,10 @@ public final class Guardrails implements GuardrailsMBean
/**
* 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");
public static final EnableFlag createSecondaryIndexesEnabled =
new EnableFlag("secondary_indexes",
state -> CONFIG_PROVIDER.getOrCreate(state).getSecondaryIndexesEnabled(),
"User creation of secondary indexes");

/**
* Guardrail on the number of materialized views per table.
@@ -135,36 +135,36 @@ public final class Guardrails implements GuardrailsMBean
/**
* Guardrail disabling user-provided timestamps.
*/
public static final DisableFlag userTimestampsEnabled =
new DisableFlag("user_timestamps",
state -> !CONFIG_PROVIDER.getOrCreate(state).getUserTimestampsEnabled(),
"User provided timestamps (USING TIMESTAMP)");
public static final EnableFlag userTimestampsEnabled =
new EnableFlag("user_timestamps",
state -> CONFIG_PROVIDER.getOrCreate(state).getUserTimestampsEnabled(),
"User provided timestamps (USING TIMESTAMP)");

public static final DisableFlag groupByEnabled =
new DisableFlag("group_by",
state -> !CONFIG_PROVIDER.getOrCreate(state).getGroupByEnabled(),
"GROUP BY functionality");
public static final EnableFlag groupByEnabled =
new EnableFlag("group_by",
state -> CONFIG_PROVIDER.getOrCreate(state).getGroupByEnabled(),
"GROUP BY functionality");

public static final DisableFlag dropTruncateTableEnabled =
new DisableFlag("drop_truncate_table_enabled",
state -> !CONFIG_PROVIDER.getOrCreate(state).getDropTruncateTableEnabled(),
"DROP and TRUNCATE TABLE functionality");
public static final EnableFlag dropTruncateTableEnabled =
new EnableFlag("drop_truncate_table_enabled",
state -> CONFIG_PROVIDER.getOrCreate(state).getDropTruncateTableEnabled(),
"DROP and TRUNCATE TABLE functionality");

/**
* Guardrail disabling user's ability to turn off compression
*/
public static final DisableFlag uncompressedTablesEnabled =
new DisableFlag("uncompressed_tables_enabled",
state -> !CONFIG_PROVIDER.getOrCreate(state).getUncompressedTablesEnabled(),
"Uncompressed table");
public static final EnableFlag uncompressedTablesEnabled =
new EnableFlag("uncompressed_tables_enabled",
state -> CONFIG_PROVIDER.getOrCreate(state).getUncompressedTablesEnabled(),
"Uncompressed table");

/**
* Guardrail disabling the creation of new COMPACT STORAGE tables
*/
public static final DisableFlag compactTablesEnabled =
new DisableFlag("compact_tables",
state -> !CONFIG_PROVIDER.getOrCreate(state).getCompactTablesEnabled(),
"Creation of new COMPACT STORAGE tables");
public static final EnableFlag compactTablesEnabled =
new EnableFlag("compact_tables",
state -> CONFIG_PROVIDER.getOrCreate(state).getCompactTablesEnabled(),
"Creation of new COMPACT STORAGE tables");

/**
* Guardrail on the number of elements returned within page.
@@ -197,18 +197,18 @@ public final class Guardrails implements GuardrailsMBean
/**
* Guardrail disabling operations on lists that require read before write.
*/
public static final DisableFlag readBeforeWriteListOperationsEnabled =
new DisableFlag("read_before_write_list_operations",
state -> !CONFIG_PROVIDER.getOrCreate(state).getReadBeforeWriteListOperationsEnabled(),
"List operation requiring read before write");
public static final EnableFlag readBeforeWriteListOperationsEnabled =
new EnableFlag("read_before_write_list_operations",
state -> CONFIG_PROVIDER.getOrCreate(state).getReadBeforeWriteListOperationsEnabled(),
"List operation requiring read before write");

/**
* Guardrail disabling ALLOW FILTERING statement within a query
*/
public static final DisableFlag allowFilteringEnabled =
new DisableFlag("allow_filtering",
state -> !CONFIG_PROVIDER.getOrCreate(state).getAllowFilteringEnabled(),
"Querying with ALLOW FILTERING");
public static final EnableFlag allowFilteringEnabled =
new EnableFlag("allow_filtering",
state -> CONFIG_PROVIDER.getOrCreate(state).getAllowFilteringEnabled(),
"Querying with ALLOW FILTERING");

/**
* Guardrail on the number of restrictions created by a cartesian product of a CQL's {@code IN} query.
@@ -67,8 +67,8 @@ public void testMaxThreshold() throws Throwable
MaxThreshold guard = new MaxThreshold("x",
state -> 10,
state -> 100,
(isWarn, what, v, t) -> format("%s: for %s, %s > %s",
isWarn ? "Warning" : "Aborting", what, v, t));
(isWarn, featureName, v, t) -> format("%s: for %s, %s > %s",
isWarn ? "Warning" : "Aborting", featureName, v, t));

assertTrue(guard.enabled(userClientState));

@@ -93,8 +93,8 @@ public void testWarnOnlyMaxThreshold() throws Throwable
MaxThreshold guard = new MaxThreshold("x",
state -> 10,
state -> DISABLED,
(isWarn, what, v, t) -> format("%s: for %s, %s > %s",
isWarn ? "Warning" : "Aborting", what, v, t));
(isWarn, featureName, v, t) -> format("%s: for %s, %s > %s",
isWarn ? "Warning" : "Aborting", featureName, v, t));

assertTrue(guard.enabled(userClientState));

@@ -111,8 +111,8 @@ public void testFailOnlyMaxThreshold() throws Throwable
MaxThreshold guard = new MaxThreshold("x",
state -> DISABLED,
state -> 10,
(isWarn, what, v, t) -> format("%s: for %s, %s > %s",
isWarn ? "Warning" : "Aborting", what, v, t));
(isWarn, featureName, v, t) -> format("%s: for %s, %s > %s",
isWarn ? "Warning" : "Aborting", featureName, v, t));

assertTrue(guard.enabled(userClientState));

@@ -129,8 +129,8 @@ public void testMaxThresholdUsers() throws Throwable
MaxThreshold guard = new MaxThreshold("x",
state -> 10,
state -> 100,
(isWarn, what, v, t) -> format("%s: for %s, %s > %s",
isWarn ? "Warning" : "Failure", what, v, t));
(isWarn, featureName, v, t) -> format("%s: for %s, %s > %s",
isWarn ? "Warning" : "Failure", featureName, v, t));

// value under both thresholds
assertValid(() -> guard.guard(5, "x", false, null));
@@ -251,25 +251,25 @@ public void testMinThresholdUsers() throws Throwable
}

@Test
public void testDisableFlag() throws Throwable
public void testEnableFlag() throws Throwable
{
assertFails(() -> new DisableFlag("x", state -> true, "X").ensureEnabled(userClientState), "X is not allowed");
assertValid(() -> new DisableFlag("x", state -> false, "X").ensureEnabled(userClientState));
assertFails(() -> new EnableFlag("x", state -> false, "X").ensureEnabled(userClientState), "X is not allowed");
assertValid(() -> new EnableFlag("x", state -> true, "X").ensureEnabled(userClientState));

assertFails(() -> new DisableFlag("x", state -> true, "X").ensureEnabled("Y", userClientState), "Y is not allowed");
assertValid(() -> new DisableFlag("x", state -> false, "X").ensureEnabled("Y", userClientState));
assertFails(() -> new EnableFlag("x", state -> false, "X").ensureEnabled("Y", userClientState), "Y is not allowed");
assertValid(() -> new EnableFlag("x", state -> true, "X").ensureEnabled("Y", userClientState));
}

@Test
public void testDisableFlagUsers() throws Throwable
public void testEnableFlagUsers() throws Throwable
{
DisableFlag enabled = new DisableFlag("x", state -> false, "X");
EnableFlag enabled = new EnableFlag("x", state -> true, "X");
assertValid(() -> enabled.ensureEnabled(null));
assertValid(() -> enabled.ensureEnabled(userClientState));
assertValid(() -> enabled.ensureEnabled(systemClientState));
assertValid(() -> enabled.ensureEnabled(superClientState));

DisableFlag disabled = new DisableFlag("x", state -> true, "X");
EnableFlag disabled = new EnableFlag("x", state -> false, "X");
assertFails(() -> disabled.ensureEnabled(userClientState), "X is not allowed");
assertValid(() -> disabled.ensureEnabled(systemClientState));
assertValid(() -> disabled.ensureEnabled(superClientState));

0 comments on commit 013acc6

Please sign in to comment.