You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by az...@apache.org on 2022/01/10 09:19:31 UTC

[cassandra] branch trunk updated: Make capacity/validity/updateinterval/activeupdate for Auth Caches configurable via nodetool

This is an automated email from the ASF dual-hosted git repository.

azotcsit pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new bc20bdd  Make capacity/validity/updateinterval/activeupdate for Auth Caches configurable via nodetool
bc20bdd is described below

commit bc20bddcebd6a37b14cfbdd50c359be4c9743f73
Author: Aleksei Zotov <az...@gmail.com>
AuthorDate: Mon Dec 20 21:26:41 2021 +0400

    Make capacity/validity/updateinterval/activeupdate for Auth Caches configurable via nodetool
    
    patch by Aleksei Zotov; reviewed by Josh McKenzie for CASSANDRA-17063
---
 CHANGES.txt                                        |   1 +
 NEWS.txt                                           |   1 +
 src/java/org/apache/cassandra/tools/NodeProbe.java |  20 +++
 src/java/org/apache/cassandra/tools/NodeTool.java  |   2 +
 .../tools/nodetool/GetAuthCacheConfig.java         |  47 +++++
 .../tools/nodetool/InvalidatePermissionsCache.java |   2 +-
 .../tools/nodetool/SetAuthCacheConfig.java         | 114 +++++++++++++
 .../tools/nodetool/GetAuthCacheConfigTest.java     | 141 +++++++++++++++
 .../nodetool/InvalidateCredentialsCacheTest.java   |  14 +-
 .../InvalidateJmxPermissionsCacheTest.java         |  21 ++-
 .../InvalidateNetworkPermissionsCacheTest.java     |  12 +-
 .../nodetool/InvalidatePermissionsCacheTest.java   |  16 +-
 .../tools/nodetool/InvalidateRolesCacheTest.java   |  12 +-
 .../tools/nodetool/SetAuthCacheConfigTest.java     | 189 +++++++++++++++++++++
 14 files changed, 549 insertions(+), 43 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 9cf76fd..2ef9307 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 4.1
+ * Make capacity/validity/updateinterval/activeupdate for Auth Caches configurable via nodetool (CASSANDRA-17063)
  * Added startup check for read_ahead_kb setting (CASSANDRA-16436)
  * Avoid unecessary array allocations and initializations when performing query checks (CASSANDRA-17209)
  * Add guardrail for list operations that require read before write (CASSANDRA-17154)
diff --git a/NEWS.txt b/NEWS.txt
index b46fb56..ffa909d 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -38,6 +38,7 @@ using the provided 'sstableupgrade' tool.
 
 New features
 ------------
+    - Added ability to configure auth caches through corresponding `nodetool` commands.
     - CDC data flushing now can be configured to be non-blocking with the configuration cdc_block_writes. Setting to true,
       any writes to the CDC-enabled tables will be blocked when reaching to the limit for CDC data on disk, which is the
       existing and the default behavior. Setting to false, the writes to the CDC-enabled tables will be accepted and
diff --git a/src/java/org/apache/cassandra/tools/NodeProbe.java b/src/java/org/apache/cassandra/tools/NodeProbe.java
index 1347aa0..73d2cbf 100644
--- a/src/java/org/apache/cassandra/tools/NodeProbe.java
+++ b/src/java/org/apache/cassandra/tools/NodeProbe.java
@@ -61,6 +61,7 @@ import org.apache.cassandra.audit.AuditLogOptions;
 import org.apache.cassandra.audit.AuditLogOptionsCompositeData;
 import com.google.common.collect.ImmutableMap;
 import org.apache.cassandra.auth.AuthCache;
+import org.apache.cassandra.auth.AuthCacheMBean;
 import org.apache.cassandra.auth.NetworkPermissionsCache;
 import org.apache.cassandra.auth.NetworkPermissionsCacheMBean;
 import org.apache.cassandra.auth.PasswordAuthenticator;
@@ -569,6 +570,25 @@ public class NodeProbe implements AutoCloseable
         cacheService.invalidateRowCache();
     }
 
+    public AuthCacheMBean getAuthCacheMBean(String cacheName)
+    {
+        switch (cacheName)
+        {
+            case PasswordAuthenticator.CredentialsCacheMBean.CACHE_NAME:
+                return ccProxy;
+            case AuthorizationProxy.JmxPermissionsCacheMBean.CACHE_NAME:
+                return jpcProxy;
+            case NetworkPermissionsCacheMBean.CACHE_NAME:
+                return npcProxy;
+            case PermissionsCacheMBean.CACHE_NAME:
+                return pcProxy;
+            case RolesCacheMBean.CACHE_NAME:
+                return rcProxy;
+            default:
+                throw new IllegalArgumentException("Unknown cache name: " + cacheName);
+        }
+    }
+
     public void drain() throws IOException, InterruptedException, ExecutionException
     {
         ssProxy.drain();
diff --git a/src/java/org/apache/cassandra/tools/NodeTool.java b/src/java/org/apache/cassandra/tools/NodeTool.java
index dd85f10..f9422bd 100644
--- a/src/java/org/apache/cassandra/tools/NodeTool.java
+++ b/src/java/org/apache/cassandra/tools/NodeTool.java
@@ -129,6 +129,7 @@ public class NodeTool
                 GarbageCollect.class,
                 GcStats.class,
                 GetAuditLog.class,
+                GetAuthCacheConfig.class,
                 GetBatchlogReplayTrottle.class,
                 GetColumnIndexSize.class,
                 GetCompactionThreshold.class,
@@ -187,6 +188,7 @@ public class NodeTool
                 ResumeHandoff.class,
                 Ring.class,
                 Scrub.class,
+                SetAuthCacheConfig.class,
                 SetBatchlogReplayThrottle.class,
                 SetCacheCapacity.class,
                 SetCacheKeysToSave.class,
diff --git a/src/java/org/apache/cassandra/tools/nodetool/GetAuthCacheConfig.java b/src/java/org/apache/cassandra/tools/nodetool/GetAuthCacheConfig.java
new file mode 100644
index 0000000..347500b
--- /dev/null
+++ b/src/java/org/apache/cassandra/tools/nodetool/GetAuthCacheConfig.java
@@ -0,0 +1,47 @@
+/*
+ * 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.tools.nodetool;
+
+import io.airlift.airline.Command;
+import io.airlift.airline.Option;
+import org.apache.cassandra.auth.AuthCacheMBean;
+import org.apache.cassandra.tools.NodeProbe;
+import org.apache.cassandra.tools.NodeTool;
+
+@Command(name = "getauthcacheconfig", description = "Get configuration of Auth cache")
+public class GetAuthCacheConfig extends NodeTool.NodeToolCmd
+{
+    @SuppressWarnings("unused")
+    @Option(title = "cache-name",
+            name = {"--cache-name"},
+            description = "Name of Auth cache (required)",
+            required = true)
+    private String cacheName;
+
+    @Override
+    public void execute(NodeProbe probe)
+    {
+        AuthCacheMBean authCacheMBean = probe.getAuthCacheMBean(cacheName);
+
+        probe.output().out.println("Validity Period: " + authCacheMBean.getValidity());
+        probe.output().out.println("Update Interval: " + authCacheMBean.getUpdateInterval());
+        probe.output().out.println("Max Entries: " + authCacheMBean.getMaxEntries());
+        probe.output().out.println("Active Update: " + authCacheMBean.getActiveUpdate());
+    }
+}
diff --git a/src/java/org/apache/cassandra/tools/nodetool/InvalidatePermissionsCache.java b/src/java/org/apache/cassandra/tools/nodetool/InvalidatePermissionsCache.java
index f879f27..cc66c98 100644
--- a/src/java/org/apache/cassandra/tools/nodetool/InvalidatePermissionsCache.java
+++ b/src/java/org/apache/cassandra/tools/nodetool/InvalidatePermissionsCache.java
@@ -182,7 +182,7 @@ public class InvalidatePermissionsCache extends NodeToolCmd
             return FunctionResource.fromName("functions/" + functionsInKeyspace + '/' + function).getName();
         } catch (ConfigurationException e)
         {
-            throw new IllegalArgumentException("An error was encountered when looking up function definition; " + e.getMessage());
+            throw new IllegalArgumentException("An error was encountered when looking up function definition: " + e.getMessage());
         }
     }
 }
\ No newline at end of file
diff --git a/src/java/org/apache/cassandra/tools/nodetool/SetAuthCacheConfig.java b/src/java/org/apache/cassandra/tools/nodetool/SetAuthCacheConfig.java
new file mode 100644
index 0000000..8adad65
--- /dev/null
+++ b/src/java/org/apache/cassandra/tools/nodetool/SetAuthCacheConfig.java
@@ -0,0 +1,114 @@
+/*
+ * 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.tools.nodetool;
+
+import io.airlift.airline.Command;
+import io.airlift.airline.Option;
+import org.apache.cassandra.auth.AuthCacheMBean;
+import org.apache.cassandra.tools.NodeProbe;
+import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+@Command(name = "setauthcacheconfig", description = "Set configuration for Auth cache")
+public class SetAuthCacheConfig extends NodeToolCmd
+{
+    @SuppressWarnings("unused")
+    @Option(title = "cache-name",
+            name = {"--cache-name"},
+            description = "Name of Auth cache (required)",
+            required = true)
+    private String cacheName;
+
+    @SuppressWarnings("unused")
+    @Option(title = "validity-period",
+            name = {"--validity-period"},
+            description = "Validity period in milliseconds")
+    private Integer validityPeriod;
+
+    @SuppressWarnings("unused")
+    @Option(title = "update-interval",
+            name = {"--update-interval"},
+            description = "Update interval in milliseconds")
+    private Integer updateInterval;
+
+    @SuppressWarnings("unused")
+    @Option(title = "max-entries",
+            name = {"--max-entries"},
+            description = "Max entries")
+    private Integer maxEntries;
+
+    @SuppressWarnings("unused")
+    @Option(title = "enable-active-update",
+            name = {"--enable-active-update"},
+            description = "Enable active update")
+    private Boolean enableActiveUpdate;
+
+    @SuppressWarnings("unused")
+    @Option(title = "disable-active-update",
+            name = {"--disable-active-update"},
+            description = "Disable active update")
+    private Boolean disableActiveUpdate;
+
+    @Override
+    public void execute(NodeProbe probe)
+    {
+        Boolean activeUpdate = getActiveUpdate(enableActiveUpdate, disableActiveUpdate);
+
+        checkArgument(validityPeriod != null || updateInterval != null
+                      || maxEntries != null || activeUpdate != null,
+                      "At least one optional parameter need to be passed");
+
+        AuthCacheMBean authCacheMBean = probe.getAuthCacheMBean(cacheName);
+
+        if (validityPeriod != null)
+        {
+            authCacheMBean.setValidity(validityPeriod);
+            probe.output().out.println("Changed Validity Period to " + validityPeriod);
+        }
+
+        if (updateInterval != null)
+        {
+            authCacheMBean.setUpdateInterval(updateInterval);
+            probe.output().out.println("Changed Update Interval to " + updateInterval);
+        }
+
+        if (maxEntries != null)
+        {
+            authCacheMBean.setMaxEntries(maxEntries);
+            probe.output().out.println("Changed Max Entries to " + maxEntries);
+        }
+
+        if (activeUpdate != null)
+        {
+            authCacheMBean.setActiveUpdate(activeUpdate);
+            probe.output().out.println("Changed Active Update to " + activeUpdate);
+        }
+    }
+
+    private Boolean getActiveUpdate(Boolean enableActiveUpdate, Boolean disableActiveUpdate)
+    {
+        if (enableActiveUpdate == null && disableActiveUpdate == null)
+            return null;
+
+        if (enableActiveUpdate != null && disableActiveUpdate != null)
+            throw new IllegalArgumentException("enable-active-update and disable-active-update cannot be used together");
+
+        return Boolean.TRUE.equals(enableActiveUpdate) ? Boolean.TRUE : Boolean.FALSE;
+    }
+}
diff --git a/test/unit/org/apache/cassandra/tools/nodetool/GetAuthCacheConfigTest.java b/test/unit/org/apache/cassandra/tools/nodetool/GetAuthCacheConfigTest.java
new file mode 100644
index 0000000..6afc179
--- /dev/null
+++ b/test/unit/org/apache/cassandra/tools/nodetool/GetAuthCacheConfigTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.tools.nodetool;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.cassandra.auth.AuthCache;
+import org.apache.cassandra.auth.AuthenticatedUser;
+import org.apache.cassandra.auth.NetworkPermissionsCacheMBean;
+import org.apache.cassandra.auth.PasswordAuthenticator;
+import org.apache.cassandra.auth.PermissionsCacheMBean;
+import org.apache.cassandra.auth.Roles;
+import org.apache.cassandra.auth.RolesCacheMBean;
+import org.apache.cassandra.auth.jmx.AuthorizationProxy;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.tools.ToolRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class GetAuthCacheConfigTest extends CQLTester
+{
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        CQLTester.setUpClass();
+        CQLTester.requireAuthentication();
+        startJMXServer();
+    }
+
+    @Test
+    @SuppressWarnings("SingleCharacterStringConcatenation")
+    public void testMaybeChangeDocs()
+    {
+        // If you added, modified options or help, please update docs if necessary
+        ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("help", "getauthcacheconfig");
+        tool.assertOnCleanExit();
+
+        String help = "NAME\n" +
+                      "        nodetool getauthcacheconfig - Get configuration of Auth cache\n" +
+                      "\n" +
+                      "SYNOPSIS\n" +
+                      "        nodetool [(-h <host> | --host <host>)] [(-p <port> | --port <port>)]\n" +
+                      "                [(-pp | --print-port)] [(-pw <password> | --password <password>)]\n" +
+                      "                [(-pwf <passwordFilePath> | --password-file <passwordFilePath>)]\n" +
+                      "                [(-u <username> | --username <username>)] getauthcacheconfig\n" +
+                      "                --cache-name <cache-name>\n" +
+                      "\n" +
+                      "OPTIONS\n" +
+                      "        --cache-name <cache-name>\n" +
+                      "            Name of Auth cache (required)\n" +
+                      "\n" +
+                      "        -h <host>, --host <host>\n" +
+                      "            Node hostname or ip address\n" +
+                      "\n" +
+                      "        -p <port>, --port <port>\n" +
+                      "            Remote jmx agent port number\n" +
+                      "\n" +
+                      "        -pp, --print-port\n" +
+                      "            Operate in 4.0 mode with hosts disambiguated by port number\n" +
+                      "\n" +
+                      "        -pw <password>, --password <password>\n" +
+                      "            Remote jmx agent password\n" +
+                      "\n" +
+                      "        -pwf <passwordFilePath>, --password-file <passwordFilePath>\n" +
+                      "            Path to the JMX password file\n" +
+                      "\n" +
+                      "        -u <username>, --username <username>\n" +
+                      "            Remote jmx agent username\n" +
+                      "\n" +
+                      "\n";
+        assertThat(tool.getStdout()).isEqualTo(help);
+    }
+
+    @Test
+    public void testInvalidCacheName()
+    {
+        ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("getauthcacheconfig");
+        assertThat(tool.getExitCode()).isEqualTo(1);
+        assertThat(tool.getStdout()).isEqualTo(wrapByDefaultNodetoolMessage("Required option '--cache-name' is missing"));
+        assertThat(tool.getStderr()).isEmpty();
+
+        tool = ToolRunner.invokeNodetool("getauthcacheconfig", "--cache-name");
+        assertThat(tool.getExitCode()).isEqualTo(1);
+        assertThat(tool.getStdout()).isEqualTo(wrapByDefaultNodetoolMessage("Required values for option 'cache-name' not provided"));
+        assertThat(tool.getStderr()).isEmpty();
+
+        tool = ToolRunner.invokeNodetool("getauthcacheconfig", "--cache-name", "wrong");
+        assertThat(tool.getExitCode()).isEqualTo(1);
+        assertThat(tool.getStdout()).isEqualTo(wrapByDefaultNodetoolMessage("Unknown cache name: wrong"));
+        assertThat(tool.getStderr()).isEmpty();
+    }
+
+    @Test
+    public void testGetConfig()
+    {
+        assertGetConfig(AuthenticatedUser.permissionsCache, PermissionsCacheMBean.CACHE_NAME);
+
+        PasswordAuthenticator passwordAuthenticator = (PasswordAuthenticator) DatabaseDescriptor.getAuthenticator();
+        assertGetConfig(passwordAuthenticator.getCredentialsCache(), PasswordAuthenticator.CredentialsCacheMBean.CACHE_NAME);
+
+        assertGetConfig(AuthorizationProxy.jmxPermissionsCache, AuthorizationProxy.JmxPermissionsCacheMBean.CACHE_NAME);
+
+        assertGetConfig(AuthenticatedUser.networkPermissionsCache, NetworkPermissionsCacheMBean.CACHE_NAME);
+
+        assertGetConfig(Roles.cache, RolesCacheMBean.CACHE_NAME);
+    }
+
+    @SuppressWarnings("SingleCharacterStringConcatenation")
+    private void assertGetConfig(AuthCache<?, ?> authCache, String cacheName)
+    {
+        ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("getauthcacheconfig", "--cache-name", cacheName);
+        tool.assertOnCleanExit();
+        assertThat(tool.getStdout()).isEqualTo("Validity Period: " + authCache.getValidity() + "\n" +
+                                               "Update Interval: " + authCache.getUpdateInterval() + "\n" +
+                                               "Max Entries: " + authCache.getMaxEntries() + "\n" +
+                                               "Active Update: " + authCache.getActiveUpdate() + "\n");
+    }
+
+    private String wrapByDefaultNodetoolMessage(String s)
+    {
+        return "nodetool: " + s + "\nSee 'nodetool help' or 'nodetool help <command>'.\n";
+    }
+}
diff --git a/test/unit/org/apache/cassandra/tools/nodetool/InvalidateCredentialsCacheTest.java b/test/unit/org/apache/cassandra/tools/nodetool/InvalidateCredentialsCacheTest.java
index a6c5d284..40d7ffb 100644
--- a/test/unit/org/apache/cassandra/tools/nodetool/InvalidateCredentialsCacheTest.java
+++ b/test/unit/org/apache/cassandra/tools/nodetool/InvalidateCredentialsCacheTest.java
@@ -23,11 +23,12 @@ import org.junit.Test;
 
 import com.datastax.driver.core.EndPoint;
 import com.datastax.driver.core.PlainTextAuthProvider;
-import org.apache.cassandra.SchemaLoader;
 import org.apache.cassandra.auth.AuthTestUtils;
 import org.apache.cassandra.auth.AuthenticatedUser;
 import org.apache.cassandra.auth.IAuthenticator;
+import org.apache.cassandra.auth.IRoleManager;
 import org.apache.cassandra.auth.PasswordAuthenticator;
+import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.cql3.CQLTester;
 import org.apache.cassandra.tools.ToolRunner;
 
@@ -44,17 +45,14 @@ public class InvalidateCredentialsCacheTest extends CQLTester
     @BeforeClass
     public static void setup() throws Exception
     {
-        SchemaLoader.prepareServer();
-        AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
-        PasswordAuthenticator passwordAuthenticator = new AuthTestUtils.LocalPasswordAuthenticator();
-        SchemaLoader.setupAuth(roleManager,
-                               passwordAuthenticator,
-                               new AuthTestUtils.LocalCassandraAuthorizer(),
-                               new AuthTestUtils.LocalCassandraNetworkAuthorizer());
+        CQLTester.setUpClass();
+        CQLTester.requireAuthentication();
 
+        IRoleManager roleManager = DatabaseDescriptor.getRoleManager();
         roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
         roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
 
+        PasswordAuthenticator passwordAuthenticator = (PasswordAuthenticator) DatabaseDescriptor.getAuthenticator();
         roleANegotiator = passwordAuthenticator.newSaslNegotiator(null);
         roleANegotiator.evaluateResponse(new PlainTextAuthProvider(ROLE_A.getRoleName(), "ignored")
                 .newAuthenticator((EndPoint) null, null)
diff --git a/test/unit/org/apache/cassandra/tools/nodetool/InvalidateJmxPermissionsCacheTest.java b/test/unit/org/apache/cassandra/tools/nodetool/InvalidateJmxPermissionsCacheTest.java
index 484f5e7..edb6578 100644
--- a/test/unit/org/apache/cassandra/tools/nodetool/InvalidateJmxPermissionsCacheTest.java
+++ b/test/unit/org/apache/cassandra/tools/nodetool/InvalidateJmxPermissionsCacheTest.java
@@ -24,13 +24,15 @@ import javax.security.auth.Subject;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import org.apache.cassandra.SchemaLoader;
 import org.apache.cassandra.auth.AuthTestUtils;
 import org.apache.cassandra.auth.AuthenticatedUser;
 import org.apache.cassandra.auth.CassandraPrincipal;
+import org.apache.cassandra.auth.IAuthorizer;
+import org.apache.cassandra.auth.IRoleManager;
 import org.apache.cassandra.auth.JMXResource;
 import org.apache.cassandra.auth.Permission;
 import org.apache.cassandra.auth.jmx.AuthorizationProxy;
+import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.cql3.CQLTester;
 import org.apache.cassandra.tools.ToolRunner;
 
@@ -46,21 +48,18 @@ public class InvalidateJmxPermissionsCacheTest extends CQLTester
     @BeforeClass
     public static void setup() throws Exception
     {
-        SchemaLoader.prepareServer();
-        AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
-        AuthTestUtils.LocalCassandraAuthorizer authorizer = new AuthTestUtils.LocalCassandraAuthorizer();
-        SchemaLoader.setupAuth(roleManager,
-                               new AuthTestUtils.LocalPasswordAuthenticator(),
-                               authorizer,
-                               new AuthTestUtils.LocalCassandraNetworkAuthorizer());
+        CQLTester.setUpClass();
+        CQLTester.requireAuthentication();
+
+        IRoleManager roleManager = DatabaseDescriptor.getRoleManager();
+        roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
+        roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
 
         JMXResource rootJmxResource = JMXResource.root();
         Set<Permission> jmxPermissions = rootJmxResource.applicablePermissions();
 
-        roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
+        IAuthorizer authorizer = DatabaseDescriptor.getAuthorizer();
         authorizer.grant(AuthenticatedUser.SYSTEM_USER, jmxPermissions, rootJmxResource, ROLE_A);
-
-        roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
         authorizer.grant(AuthenticatedUser.SYSTEM_USER, jmxPermissions, rootJmxResource, ROLE_B);
 
         startJMXServer();
diff --git a/test/unit/org/apache/cassandra/tools/nodetool/InvalidateNetworkPermissionsCacheTest.java b/test/unit/org/apache/cassandra/tools/nodetool/InvalidateNetworkPermissionsCacheTest.java
index a693eca..d68994d 100644
--- a/test/unit/org/apache/cassandra/tools/nodetool/InvalidateNetworkPermissionsCacheTest.java
+++ b/test/unit/org/apache/cassandra/tools/nodetool/InvalidateNetworkPermissionsCacheTest.java
@@ -21,9 +21,10 @@ package org.apache.cassandra.tools.nodetool;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import org.apache.cassandra.SchemaLoader;
 import org.apache.cassandra.auth.AuthTestUtils;
 import org.apache.cassandra.auth.AuthenticatedUser;
+import org.apache.cassandra.auth.IRoleManager;
+import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.cql3.CQLTester;
 import org.apache.cassandra.tools.ToolRunner;
 
@@ -37,13 +38,10 @@ public class InvalidateNetworkPermissionsCacheTest extends CQLTester
     @BeforeClass
     public static void setup() throws Exception
     {
-        SchemaLoader.prepareServer();
-        AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
-        SchemaLoader.setupAuth(roleManager,
-                               new AuthTestUtils.LocalPasswordAuthenticator(),
-                               new AuthTestUtils.LocalCassandraAuthorizer(),
-                               new AuthTestUtils.LocalCassandraNetworkAuthorizer());
+        CQLTester.setUpClass();
+        CQLTester.requireAuthentication();
 
+        IRoleManager roleManager = DatabaseDescriptor.getRoleManager();
         roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
         roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
 
diff --git a/test/unit/org/apache/cassandra/tools/nodetool/InvalidatePermissionsCacheTest.java b/test/unit/org/apache/cassandra/tools/nodetool/InvalidatePermissionsCacheTest.java
index 91d36ab..fdd0bf7 100644
--- a/test/unit/org/apache/cassandra/tools/nodetool/InvalidatePermissionsCacheTest.java
+++ b/test/unit/org/apache/cassandra/tools/nodetool/InvalidatePermissionsCacheTest.java
@@ -28,12 +28,13 @@ import org.apache.commons.lang3.StringUtils;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import org.apache.cassandra.SchemaLoader;
 import org.apache.cassandra.auth.AuthTestUtils;
 import org.apache.cassandra.auth.AuthenticatedUser;
 import org.apache.cassandra.auth.DataResource;
 import org.apache.cassandra.auth.FunctionResource;
+import org.apache.cassandra.auth.IAuthorizer;
 import org.apache.cassandra.auth.IResource;
+import org.apache.cassandra.auth.IRoleManager;
 import org.apache.cassandra.auth.JMXResource;
 import org.apache.cassandra.auth.Permission;
 import org.apache.cassandra.auth.RoleResource;
@@ -52,14 +53,10 @@ public class InvalidatePermissionsCacheTest extends CQLTester
     @BeforeClass
     public static void setup() throws Exception
     {
-        SchemaLoader.prepareServer();
-        AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
-        AuthTestUtils.LocalCassandraAuthorizer authorizer = new AuthTestUtils.LocalCassandraAuthorizer();
-        SchemaLoader.setupAuth(roleManager,
-                               new AuthTestUtils.LocalPasswordAuthenticator(),
-                               authorizer,
-                               new AuthTestUtils.LocalCassandraNetworkAuthorizer());
+        CQLTester.setUpClass();
+        CQLTester.requireAuthentication();
 
+        IRoleManager roleManager = DatabaseDescriptor.getRoleManager();
         roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
         roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
 
@@ -78,6 +75,7 @@ public class InvalidatePermissionsCacheTest extends CQLTester
                 JMXResource.root(),
                 JMXResource.mbean("org.apache.cassandra.auth:type=*"));
 
+        IAuthorizer authorizer = DatabaseDescriptor.getAuthorizer();
         for (IResource resource : resources)
         {
             Set<Permission> permissions = resource.applicablePermissions();
@@ -221,7 +219,7 @@ public class InvalidatePermissionsCacheTest extends CQLTester
                 KEYSPACE, "--function", "f[x]");
         assertThat(tool.getExitCode()).isEqualTo(1);
         assertThat(tool.getStdout())
-                .isEqualTo(wrapByDefaultNodetoolMessage("An error was encountered when looking up function definition; Unable to find abstract-type class 'org.apache.cassandra.db.marshal.x'"));
+                .isEqualTo(wrapByDefaultNodetoolMessage("An error was encountered when looking up function definition: Unable to find abstract-type class 'org.apache.cassandra.db.marshal.x'"));
         assertThat(tool.getStderr()).isEmpty();
     }
 
diff --git a/test/unit/org/apache/cassandra/tools/nodetool/InvalidateRolesCacheTest.java b/test/unit/org/apache/cassandra/tools/nodetool/InvalidateRolesCacheTest.java
index 266768d..99cfb38 100644
--- a/test/unit/org/apache/cassandra/tools/nodetool/InvalidateRolesCacheTest.java
+++ b/test/unit/org/apache/cassandra/tools/nodetool/InvalidateRolesCacheTest.java
@@ -21,9 +21,10 @@ package org.apache.cassandra.tools.nodetool;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import org.apache.cassandra.SchemaLoader;
 import org.apache.cassandra.auth.AuthTestUtils;
 import org.apache.cassandra.auth.AuthenticatedUser;
+import org.apache.cassandra.auth.IRoleManager;
+import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.cql3.CQLTester;
 import org.apache.cassandra.tools.ToolRunner;
 
@@ -37,13 +38,10 @@ public class InvalidateRolesCacheTest extends CQLTester
     @BeforeClass
     public static void setup() throws Exception
     {
-        SchemaLoader.prepareServer();
-        AuthTestUtils.LocalCassandraRoleManager roleManager = new AuthTestUtils.LocalCassandraRoleManager();
-        SchemaLoader.setupAuth(roleManager,
-                               new AuthTestUtils.LocalPasswordAuthenticator(),
-                               new AuthTestUtils.LocalCassandraAuthorizer(),
-                               new AuthTestUtils.LocalCassandraNetworkAuthorizer());
+        CQLTester.setUpClass();
+        CQLTester.requireAuthentication();
 
+        IRoleManager roleManager = DatabaseDescriptor.getRoleManager();
         roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_A, AuthTestUtils.getLoginRoleOptions());
         roleManager.createRole(AuthenticatedUser.SYSTEM_USER, ROLE_B, AuthTestUtils.getLoginRoleOptions());
 
diff --git a/test/unit/org/apache/cassandra/tools/nodetool/SetAuthCacheConfigTest.java b/test/unit/org/apache/cassandra/tools/nodetool/SetAuthCacheConfigTest.java
new file mode 100644
index 0000000..0ed2534
--- /dev/null
+++ b/test/unit/org/apache/cassandra/tools/nodetool/SetAuthCacheConfigTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.tools.nodetool;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.cassandra.auth.AuthCache;
+import org.apache.cassandra.auth.AuthenticatedUser;
+import org.apache.cassandra.auth.NetworkPermissionsCacheMBean;
+import org.apache.cassandra.auth.PasswordAuthenticator;
+import org.apache.cassandra.auth.PermissionsCacheMBean;
+import org.apache.cassandra.auth.Roles;
+import org.apache.cassandra.auth.RolesCacheMBean;
+import org.apache.cassandra.auth.jmx.AuthorizationProxy;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.tools.ToolRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SetAuthCacheConfigTest extends CQLTester
+{
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        CQLTester.setUpClass();
+        CQLTester.requireAuthentication();
+        startJMXServer();
+    }
+
+    @Test
+    @SuppressWarnings("SingleCharacterStringConcatenation")
+    public void testMaybeChangeDocs()
+    {
+        // If you added, modified options or help, please update docs if necessary
+        ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("help", "setauthcacheconfig");
+        tool.assertOnCleanExit();
+
+        String help = "NAME\n" +
+                      "        nodetool setauthcacheconfig - Set configuration for Auth cache\n" +
+                      "\n" +
+                      "SYNOPSIS\n" +
+                      "        nodetool [(-h <host> | --host <host>)] [(-p <port> | --port <port>)]\n" +
+                      "                [(-pp | --print-port)] [(-pw <password> | --password <password>)]\n" +
+                      "                [(-pwf <passwordFilePath> | --password-file <passwordFilePath>)]\n" +
+                      "                [(-u <username> | --username <username>)] setauthcacheconfig\n" +
+                      "                --cache-name <cache-name> [--disable-active-update]\n" +
+                      "                [--enable-active-update] [--max-entries <max-entries>]\n" +
+                      "                [--update-interval <update-interval>]\n" +
+                      "                [--validity-period <validity-period>]\n" +
+                      "\n" +
+                      "OPTIONS\n" +
+                      "        --cache-name <cache-name>\n" +
+                      "            Name of Auth cache (required)\n" +
+                      "\n" +
+                      "        --disable-active-update\n" +
+                      "            Disable active update\n" +
+                      "\n" +
+                      "        --enable-active-update\n" +
+                      "            Enable active update\n" +
+                      "\n" +
+                      "        -h <host>, --host <host>\n" +
+                      "            Node hostname or ip address\n" +
+                      "\n" +
+                      "        --max-entries <max-entries>\n" +
+                      "            Max entries\n" +
+                      "\n" +
+                      "        -p <port>, --port <port>\n" +
+                      "            Remote jmx agent port number\n" +
+                      "\n" +
+                      "        -pp, --print-port\n" +
+                      "            Operate in 4.0 mode with hosts disambiguated by port number\n" +
+                      "\n" +
+                      "        -pw <password>, --password <password>\n" +
+                      "            Remote jmx agent password\n" +
+                      "\n" +
+                      "        -pwf <passwordFilePath>, --password-file <passwordFilePath>\n" +
+                      "            Path to the JMX password file\n" +
+                      "\n" +
+                      "        -u <username>, --username <username>\n" +
+                      "            Remote jmx agent username\n" +
+                      "\n" +
+                      "        --update-interval <update-interval>\n" +
+                      "            Update interval in milliseconds\n" +
+                      "\n" +
+                      "        --validity-period <validity-period>\n" +
+                      "            Validity period in milliseconds\n" +
+                      "\n" +
+                      "\n";
+        assertThat(tool.getStdout()).isEqualTo(help);
+    }
+
+    @Test
+    public void testInvalidCacheName()
+    {
+        ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("setauthcacheconfig");
+        assertThat(tool.getExitCode()).isEqualTo(1);
+        assertThat(tool.getStdout()).isEqualTo(wrapByDefaultNodetoolMessage("Required option '--cache-name' is missing"));
+        assertThat(tool.getStderr()).isEmpty();
+
+        tool = ToolRunner.invokeNodetool("setauthcacheconfig", "--cache-name");
+        assertThat(tool.getExitCode()).isEqualTo(1);
+        assertThat(tool.getStdout()).isEqualTo(wrapByDefaultNodetoolMessage("Required values for option 'cache-name' not provided"));
+        assertThat(tool.getStderr()).isEmpty();
+
+        tool = ToolRunner.invokeNodetool("setauthcacheconfig", "--cache-name", "wrong", "--validity-period", "1");
+        assertThat(tool.getExitCode()).isEqualTo(1);
+        assertThat(tool.getStdout()).isEqualTo(wrapByDefaultNodetoolMessage("Unknown cache name: wrong"));
+        assertThat(tool.getStderr()).isEmpty();
+    }
+
+    @Test
+    public void testNoOptionalParameters()
+    {
+        ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("setauthcacheconfig", "--cache-name", "PermissionCache");
+        assertThat(tool.getExitCode()).isEqualTo(1);
+        assertThat(tool.getStdout()).isEqualTo(wrapByDefaultNodetoolMessage("At least one optional parameter need to be passed"));
+        assertThat(tool.getStderr()).isEmpty();
+    }
+
+    @Test
+    public void testBothEnableAndDisableActiveUpdate()
+    {
+        ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("setauthcacheconfig",
+                                                               "--cache-name", "PermissionCache",
+                                                               "--enable-active-update",
+                                                               "--disable-active-update");
+        assertThat(tool.getExitCode()).isEqualTo(1);
+        assertThat(tool.getStdout()).isEqualTo(wrapByDefaultNodetoolMessage("enable-active-update and disable-active-update cannot be used together"));
+        assertThat(tool.getStderr()).isEmpty();
+    }
+
+    @Test
+    public void testSetConfig()
+    {
+        assertSetConfig(AuthenticatedUser.permissionsCache, PermissionsCacheMBean.CACHE_NAME);
+
+        PasswordAuthenticator passwordAuthenticator = (PasswordAuthenticator) DatabaseDescriptor.getAuthenticator();
+        assertSetConfig(passwordAuthenticator.getCredentialsCache(), PasswordAuthenticator.CredentialsCacheMBean.CACHE_NAME);
+
+        assertSetConfig(AuthorizationProxy.jmxPermissionsCache, AuthorizationProxy.JmxPermissionsCacheMBean.CACHE_NAME);
+
+        assertSetConfig(AuthenticatedUser.networkPermissionsCache, NetworkPermissionsCacheMBean.CACHE_NAME);
+
+        assertSetConfig(Roles.cache, RolesCacheMBean.CACHE_NAME);
+    }
+
+    private void assertSetConfig(AuthCache<?, ?> authCache, String cacheName)
+    {
+        ToolRunner.ToolResult tool = ToolRunner.invokeNodetool("setauthcacheconfig",
+                                                               "--cache-name", cacheName,
+                                                               "--validity-period", "1",
+                                                               "--update-interval", "2",
+                                                               "--max-entries", "3",
+                                                               "--disable-active-update");
+        tool.assertOnCleanExit();
+        assertThat(tool.getStdout()).isEqualTo("Changed Validity Period to 1\n" +
+                                               "Changed Update Interval to 2\n" +
+                                               "Changed Max Entries to 3\n" +
+                                               "Changed Active Update to false\n");
+
+        assertThat(authCache.getValidity()).isEqualTo(1);
+        assertThat(authCache.getUpdateInterval()).isEqualTo(2);
+        assertThat(authCache.getMaxEntries()).isEqualTo(3);
+        assertThat(authCache.getActiveUpdate()).isFalse();
+    }
+
+    private String wrapByDefaultNodetoolMessage(String s)
+    {
+        return "nodetool: " + s + "\nSee 'nodetool help' or 'nodetool help <command>'.\n";
+    }
+}

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org