This is an automated email from the ASF dual-hosted git repository.
reidchan pushed a commit to branch branch-1
in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/branch-1 by this push:
new 4af4afc HBASE-21048 Get LogLevel is not working from console in
secure environment
4af4afc is described below
commit 4af4afc94f2836400b716dfaeef2c661064eb4fe
Author: Wei-Chiu Chuang <[email protected]>
AuthorDate: Tue Apr 16 13:58:46 2019 -0700
HBASE-21048 Get LogLevel is not working from console in secure environment
Signed-off-by: Reid Chan <[email protected]>
---
.../org/apache/hadoop/hbase/http/log/LogLevel.java | 236 +++++++++++--
.../apache/hadoop/hbase/http/log/TestLogLevel.java | 374 +++++++++++++++++----
2 files changed, 514 insertions(+), 96 deletions(-)
diff --git
a/hbase-server/src/main/java/org/apache/hadoop/hbase/http/log/LogLevel.java
b/hbase-server/src/main/java/org/apache/hadoop/hbase/http/log/LogLevel.java
index 7701a25..328e1b1 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/http/log/LogLevel.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/http/log/LogLevel.java
@@ -17,6 +17,9 @@
*/
package org.apache.hadoop.hbase.http.log;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Charsets;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -34,59 +37,223 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.impl.Jdk14Logger;
import org.apache.commons.logging.impl.Log4JLogger;
+import org.apache.hadoop.HadoopIllegalArgumentException;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.classification.InterfaceStability;
import org.apache.hadoop.hbase.http.HttpServer;
+import org.apache.hadoop.security.authentication.client.AuthenticatedURL;
+import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
import org.apache.hadoop.util.ServletUtil;
+import org.apache.hadoop.util.Tool;
/**
* Change log level in runtime.
*/
@InterfaceStability.Evolving
public class LogLevel {
- public static final String USAGES = "\nUsage: General options are:\n"
- + "\t[-getlevel <host:httpPort> <name>]\n"
- + "\t[-setlevel <host:httpPort> <name> <level>]\n";
+ private static final String USAGES = "\nUsage: General options are:\n"
+ + "\t[-getlevel <host:port> <classname>\n"
+ + "\t[-setlevel <host:port> <classname> <level> ";
+ public static final String PROTOCOL_HTTP = "http";
/**
* A command line implementation
*/
- public static void main(String[] args) {
- if (args.length == 3 && "-getlevel".equals(args[0])) {
- process("http://" + args[1] + "/logLevel?log=" + args[2]);
- return;
- }
- else if (args.length == 4 && "-setlevel".equals(args[0])) {
- process("http://" + args[1] + "/logLevel?log=" + args[2]
- + "&level=" + args[3]);
- return;
- }
+ public static void main(String[] args) throws Exception {
+ CLI cli = new CLI(new Configuration());
+ System.exit(cli.run(args));
+ }
+
+ /**
+ * Valid command line options.
+ */
+ private enum Operations {
+ GETLEVEL,
+ SETLEVEL,
+ UNKNOWN
+ }
+ private static void printUsage() {
System.err.println(USAGES);
System.exit(-1);
}
- private static void process(String urlstring) {
- try {
- URL url = new URL(urlstring);
- System.out.println("Connecting to " + url);
- URLConnection connection = url.openConnection();
+ @VisibleForTesting
+ static class CLI extends Configured implements Tool {
+ private Operations operation = Operations.UNKNOWN;
+ private String hostName;
+ private String className;
+ private String level;
+
+ CLI(Configuration conf) {
+ setConf(conf);
+ }
+
+ @Override
+ public int run(String[] args) throws Exception {
+ try {
+ parseArguments(args);
+ sendLogLevelRequest();
+ } catch (HadoopIllegalArgumentException e) {
+ printUsage();
+ }
+ return 0;
+ }
+
+ /**
+ * Send HTTP request to the daemon.
+ * @throws HadoopIllegalArgumentException if arguments are invalid.
+ * @throws Exception if unable to connect
+ */
+ private void sendLogLevelRequest()
+ throws HadoopIllegalArgumentException, Exception {
+ switch (operation) {
+ case GETLEVEL:
+ doGetLevel();
+ break;
+ case SETLEVEL:
+ doSetLevel();
+ break;
+ default:
+ throw new HadoopIllegalArgumentException(
+ "Expect either -getlevel or -setlevel");
+ }
+ }
+
+ public void parseArguments(String[] args) throws
+ HadoopIllegalArgumentException {
+ if (args.length == 0) {
+ throw new HadoopIllegalArgumentException("No arguments specified");
+ }
+ int nextArgIndex = 0;
+ while (nextArgIndex < args.length) {
+ switch (args[nextArgIndex]) {
+ case "-getlevel":
+ nextArgIndex = parseGetLevelArgs(args, nextArgIndex);
+ break;
+ case "-setlevel":
+ nextArgIndex = parseSetLevelArgs(args, nextArgIndex);
+ break;
+ default:
+ throw new HadoopIllegalArgumentException(
+ "Unexpected argument " + args[nextArgIndex]);
+ }
+ }
+
+ // if operation is never specified in the arguments
+ if (operation == Operations.UNKNOWN) {
+ throw new HadoopIllegalArgumentException(
+ "Must specify either -getlevel or -setlevel");
+ }
+ }
+
+ private int parseGetLevelArgs(String[] args, int index) throws
+ HadoopIllegalArgumentException {
+ // fail if multiple operations are specified in the arguments
+ if (operation != Operations.UNKNOWN) {
+ throw new HadoopIllegalArgumentException("Redundant -getlevel
command");
+ }
+ // check number of arguments is sufficient
+ if (index + 2 >= args.length) {
+ throw new HadoopIllegalArgumentException("-getlevel needs two
parameters");
+ }
+ operation = Operations.GETLEVEL;
+ hostName = args[index + 1];
+ className = args[index + 2];
+ return index + 3;
+ }
+
+ private int parseSetLevelArgs(String[] args, int index) throws
+ HadoopIllegalArgumentException {
+ // fail if multiple operations are specified in the arguments
+ if (operation != Operations.UNKNOWN) {
+ throw new HadoopIllegalArgumentException("Redundant -setlevel
command");
+ }
+ // check number of arguments is sufficient
+ if (index + 3 >= args.length) {
+ throw new HadoopIllegalArgumentException("-setlevel needs three
parameters");
+ }
+ operation = Operations.SETLEVEL;
+ hostName = args[index + 1];
+ className = args[index + 2];
+ level = args[index + 3];
+ return index + 4;
+ }
+
+ /**
+ * Send HTTP request to get log level.
+ *
+ * @throws HadoopIllegalArgumentException if arguments are invalid.
+ * @throws Exception if unable to connect
+ */
+ private void doGetLevel() throws Exception {
+ process(PROTOCOL_HTTP + "://" + hostName + "/logLevel?log=" + className);
+ }
+
+ /**
+ * Send HTTP request to set log level.
+ *
+ * @throws HadoopIllegalArgumentException if arguments are invalid.
+ * @throws Exception if unable to connect
+ */
+ private void doSetLevel() throws Exception {
+ process(PROTOCOL_HTTP + "://" + hostName + "/logLevel?log=" + className
+ + "&level=" + level);
+ }
+
+ /**
+ * Connect to the URL. Supports HTTP and supports SPNEGO
+ * authentication. It falls back to simple authentication if it fails to
+ * initiate SPNEGO.
+ *
+ * @param url the URL address of the daemon servlet
+ * @return a connected connection
+ * @throws Exception if it can not establish a connection.
+ */
+ private URLConnection connect(URL url) throws Exception {
+ AuthenticatedURL.Token token = new AuthenticatedURL.Token();
+ AuthenticatedURL aUrl;
+ URLConnection connection;
+
+ aUrl = new AuthenticatedURL(new KerberosAuthenticator());
+ connection = aUrl.openConnection(url, token);
connection.connect();
+ return connection;
+ }
- BufferedReader in = new BufferedReader(new InputStreamReader(
- connection.getInputStream()));
- for(String line; (line = in.readLine()) != null; )
- if (line.startsWith(MARKER)) {
- System.out.println(TAG.matcher(line).replaceAll(""));
+ /**
+ * Configures the client to send HTTP request to the URL.
+ * Supports SPENGO for authentication.
+ * @param urlString URL and query string to the daemon's web UI
+ * @throws Exception if unable to connect
+ */
+ private void process(String urlString) throws Exception {
+ URL url = new URL(urlString);
+ System.out.println("Connecting to " + url);
+
+ URLConnection connection = connect(url);
+
+ // read from the servlet
+
+ try (InputStreamReader streamReader =
+ new InputStreamReader(connection.getInputStream(), Charsets.UTF_8);
+ BufferedReader bufferedReader = new BufferedReader(streamReader)) {
+ String line;
+ while((line = bufferedReader.readLine()) != null) {
+ if (line.startsWith(MARKER)) {
+ System.out.println(TAG.matcher(line).replaceAll(""));
+ }
}
- in.close();
- } catch (IOException ioe) {
- System.err.println("" + ioe);
+ } catch (IOException ioe) {
+ System.err.println("" + ioe);
+ }
}
}
- static final String MARKER = "<!-- OUTPUT -->";
- static final Pattern TAG = Pattern.compile("<[^>]*>");
+ private static final String MARKER = "<!-- OUTPUT -->";
+ private static final Pattern TAG = Pattern.compile("<[^>]*>");
/**
* A servlet implementation
@@ -97,8 +264,8 @@ public class LogLevel {
private static final long serialVersionUID = 1L;
@Override
- public void doGet(HttpServletRequest request, HttpServletResponse response
- ) throws ServletException, IOException {
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
// Do the authorization
if (!HttpServer.hasAdministratorAccess(getServletContext(), request,
@@ -146,8 +313,7 @@ public class LogLevel {
+ "<input type='submit' value='Set Log Level' />"
+ "</form>";
- private static void process(org.apache.log4j.Logger log, String level,
- PrintWriter out) throws IOException {
+ private static void process(org.apache.log4j.Logger log, String level,
PrintWriter out) {
if (level != null) {
if (!level.equals(org.apache.log4j.Level.toLevel(level).toString())) {
out.println(MARKER + "Bad level : <b>" + level + "</b><br />");
@@ -161,14 +327,16 @@ public class LogLevel {
}
private static void process(java.util.logging.Logger log, String level,
- PrintWriter out) throws IOException {
+ PrintWriter out) {
if (level != null) {
log.setLevel(java.util.logging.Level.parse(level));
out.println(MARKER + "Setting Level to " + level + " ...<br />");
}
java.util.logging.Level lev;
- for(; (lev = log.getLevel()) == null; log = log.getParent());
+ while ((lev = log.getLevel()) == null) {
+ log = log.getParent();
+ }
out.println(MARKER + "Effective level: <b>" + lev + "</b><br />");
}
}
diff --git
a/hbase-server/src/test/java/org/apache/hadoop/hbase/http/log/TestLogLevel.java
b/hbase-server/src/test/java/org/apache/hadoop/hbase/http/log/TestLogLevel.java
index 15efb71..224bfcb 100644
---
a/hbase-server/src/test/java/org/apache/hadoop/hbase/http/log/TestLogLevel.java
+++
b/hbase-server/src/test/java/org/apache/hadoop/hbase/http/log/TestLogLevel.java
@@ -17,81 +17,331 @@
*/
package org.apache.hadoop.hbase.http.log;
+import static org.apache.hadoop.hbase.http.log.LogLevel.PROTOCOL_HTTP;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
-import java.io.*;
-import java.net.*;
+import java.io.File;
+import java.net.BindException;
+import java.net.URI;
+import java.security.PrivilegedExceptionAction;
+import java.util.Properties;
-import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.apache.commons.io.FileUtils;
+import org.apache.hadoop.HadoopIllegalArgumentException;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.CommonConfigurationKeys;
+import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
+import org.apache.hadoop.fs.FileUtil;
+import org.apache.hadoop.hbase.HBaseCommonTestingUtility;
import org.apache.hadoop.hbase.http.HttpServer;
+import org.apache.hadoop.hbase.http.log.LogLevel.CLI;
+import org.apache.hadoop.hbase.testclassification.MiscTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.apache.hadoop.minikdc.MiniKdc;
import org.apache.hadoop.net.NetUtils;
-import org.apache.commons.logging.*;
-import org.apache.commons.logging.impl.*;
-import org.apache.log4j.*;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authorize.AccessControlList;
+import org.apache.hadoop.test.GenericTestUtils;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-@Category(SmallTests.class)
+/**
+ * Test LogLevel.
+ */
+@Category({MiscTests.class, SmallTests.class})
public class TestLogLevel {
- static final PrintStream out = System.out;
-
- @Test (timeout=60000)
- @SuppressWarnings("deprecation")
- public void testDynamicLogLevel() throws Exception {
- String logName = TestLogLevel.class.getName();
- Log testlog = LogFactory.getLog(logName);
-
- //only test Log4JLogger
- if (testlog instanceof Log4JLogger) {
- Logger log = ((Log4JLogger)testlog).getLogger();
- log.debug("log.debug1");
- log.info("log.info1");
- log.error("log.error1");
- assertTrue(!Level.ERROR.equals(log.getEffectiveLevel()));
-
- HttpServer server = null;
+ private static File BASEDIR;
+ private static Configuration serverConf;
+ private static Configuration clientConf;
+ private static final String logName = TestLogLevel.class.getName();
+ private static final Logger log = LogManager.getLogger(logName);
+ private final static String PRINCIPAL = "loglevel.principal";
+ private final static String KEYTAB = "loglevel.keytab";
+
+ private static MiniKdc kdc;
+ private static HBaseCommonTestingUtility htu = new
HBaseCommonTestingUtility();
+
+ private static final String LOCALHOST = "localhost";
+ private static final String clientPrincipal = "client/" + LOCALHOST;
+ private static String HTTP_PRINCIPAL = "HTTP/" + LOCALHOST;
+
+ private static final File KEYTAB_FILE = new File(
+ htu.getDataTestDir("keytab").toUri().getPath());
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ BASEDIR = new File(htu.getDataTestDir().toUri().getPath());
+
+ FileUtil.fullyDelete(BASEDIR);
+ if (!BASEDIR.mkdirs()) {
+ throw new Exception("unable to create the base directory for testing");
+ }
+ serverConf = new Configuration();
+ clientConf = new Configuration();
+
+ kdc = setupMiniKdc();
+ // Create two principles: a client and a HTTP principal
+ kdc.createPrincipal(KEYTAB_FILE, clientPrincipal, HTTP_PRINCIPAL);
+ }
+
+ /**
+ * Sets up {@link MiniKdc} for testing security.
+ * Copied from HBaseTestingUtility#setupMiniKdc().
+ */
+ static private MiniKdc setupMiniKdc() throws Exception {
+ Properties conf = MiniKdc.createConf();
+ conf.put(MiniKdc.DEBUG, true);
+ MiniKdc kdc = null;
+ File dir = null;
+ // There is time lag between selecting a port and trying to bind with it.
It's possible that
+ // another service captures the port in between which'll result in
BindException.
+ boolean bindException;
+ int numTries = 0;
+ do {
try {
- server = new HttpServer.Builder().setName("..")
- .addEndpoint(new URI("http://localhost:0")).setFindPort(true)
- .build();
-
- server.start();
- String authority = NetUtils.getHostPortString(server
- .getConnectorAddress(0));
-
- //servlet
- URL url = new URL("http://" + authority + "/logLevel?log=" + logName
- + "&level=" + Level.ERROR);
- out.println("*** Connecting to " + url);
- HttpURLConnection connection = (HttpURLConnection)url.openConnection();
- connection.connect();
-
- BufferedReader in = new BufferedReader(new InputStreamReader(
- connection.getInputStream()));
- for(String line; (line = in.readLine()) != null; out.println(line));
- in.close();
- connection.disconnect();
-
- log.debug("log.debug2");
- log.info("log.info2");
- log.error("log.error2");
- assertTrue(Level.ERROR.equals(log.getEffectiveLevel()));
-
- //command line
- String[] args = {"-setlevel", authority, logName,
Level.DEBUG.toString()};
- LogLevel.main(args);
- log.debug("log.debug3");
- log.info("log.info3");
- log.error("log.error3");
- assertTrue(Level.DEBUG.equals(log.getEffectiveLevel()));
- } finally {
- if (server != null) {
- server.stop();
+ bindException = false;
+ dir = new File(htu.getDataTestDir("kdc").toUri().getPath());
+ kdc = new MiniKdc(conf, dir);
+ kdc.start();
+ } catch (BindException e) {
+ FileUtils.deleteDirectory(dir); // clean directory
+ numTries++;
+ if (numTries == 3) {
+ log.error("Failed setting up MiniKDC. Tried " + numTries + "
times.");
+ throw e;
}
+ log.error("BindException encountered when setting up MiniKdc. Trying
again.");
+ bindException = true;
}
+ } while (bindException);
+ return kdc;
+ }
+
+ @AfterClass
+ public static void tearDown() {
+ if (kdc != null) {
+ kdc.stop();
+ }
+
+ FileUtil.fullyDelete(BASEDIR);
+ }
+
+ /**
+ * Test client command line options. Does not validate server behavior.
+ * @throws Exception if commands return unexpected results.
+ */
+ @Test(timeout=120000)
+ public void testCommandOptions() throws Exception {
+ final String className = this.getClass().getName();
+
+ assertFalse(validateCommand(new String[] {"-foo" }));
+ // fail due to insufficient number of arguments
+ assertFalse(validateCommand(new String[] {}));
+ assertFalse(validateCommand(new String[] {"-getlevel" }));
+ assertFalse(validateCommand(new String[] {"-setlevel" }));
+ assertFalse(validateCommand(new String[] {"-getlevel", "foo.bar:8080" }));
+
+ // valid command arguments
+ assertTrue(validateCommand(
+ new String[] {"-getlevel", "foo.bar:8080", className }));
+ assertTrue(validateCommand(
+ new String[] {"-setlevel", "foo.bar:8080", className, "DEBUG" }));
+ assertTrue(validateCommand(
+ new String[] {"-getlevel", "foo.bar:8080", className }));
+ assertTrue(validateCommand(
+ new String[] {"-setlevel", "foo.bar:8080", className, "DEBUG" }));
+
+ // fail due to the extra argument
+ assertFalse(validateCommand(
+ new String[] {"-getlevel", "foo.bar:8080", className, "blah" }));
+ assertFalse(validateCommand(
+ new String[] {"-setlevel", "foo.bar:8080", className, "DEBUG", "blah"
}));
+ assertFalse(validateCommand(
+ new String[] {
+ "-getlevel", "foo.bar:8080", className, "-setlevel", "foo.bar:8080",
className }));
+ }
+
+ /**
+ * Check to see if a command can be accepted.
+ *
+ * @param args a String array of arguments
+ * @return true if the command can be accepted, false if not.
+ */
+ private boolean validateCommand(String[] args) {
+ CLI cli = new CLI(clientConf);
+ try {
+ cli.parseArguments(args);
+ } catch (HadoopIllegalArgumentException e) {
+ return false;
+ } catch (Exception e) {
+ // this is used to verify the command arguments only.
+ // no HadoopIllegalArgumentException = the arguments are good.
+ return true;
+ }
+ return true;
+ }
+
+ /**
+ * Creates and starts a Jetty server binding at an ephemeral port to run
+ * LogLevel servlet.
+ * @param isSpnego true if SPNEGO is enabled
+ * @return a created HttpServer object
+ * @throws Exception if unable to create or start a Jetty server
+ */
+ private HttpServer createServer(boolean isSpnego)
+ throws Exception {
+ HttpServer.Builder builder = new HttpServer.Builder()
+ .setName("..")
+ .addEndpoint(new URI(PROTOCOL_HTTP + "://localhost:0"))
+ .setFindPort(true)
+ .setConf(serverConf);
+ if (isSpnego) {
+ // Set up server Kerberos credentials.
+ // Since the server may fall back to simple authentication,
+ // use ACL to make sure the connection is Kerberos/SPNEGO authenticated.
+ builder.setSecurityEnabled(true)
+ .setUsernameConfKey(PRINCIPAL)
+ .setKeytabConfKey(KEYTAB)
+ .setACL(new AccessControlList("client"));
}
- else {
- out.println(testlog.getClass() + " not tested.");
+
+ HttpServer server = builder.build();
+ server.start();
+ return server;
+ }
+
+ private void testDynamicLogLevel(final boolean isSpnego)
+ throws Exception {
+ testDynamicLogLevel(isSpnego, Level.DEBUG.toString());
+ }
+
+ /**
+ * Run both client and server using the given protocol.
+ *
+ * @param isSpnego true if SPNEGO is enabled
+ * @throws Exception if client can't accesss server.
+ */
+ private void testDynamicLogLevel(final boolean isSpnego, final String
newLevel)
+ throws Exception {
+ Level oldLevel = log.getEffectiveLevel();
+ assertNotEquals("Get default Log Level which shouldn't be ERROR.",
+ Level.ERROR, oldLevel);
+
+ // configs needed for SPNEGO at server side
+ if (isSpnego) {
+ serverConf.set(PRINCIPAL, HTTP_PRINCIPAL);
+ serverConf.set(KEYTAB, KEYTAB_FILE.getAbsolutePath());
+
serverConf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION,
"kerberos");
+
serverConf.setBoolean(CommonConfigurationKeys.HADOOP_SECURITY_AUTHORIZATION,
true);
+ UserGroupInformation.setConfiguration(serverConf);
+ } else {
+
serverConf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION,
"simple");
+
serverConf.setBoolean(CommonConfigurationKeys.HADOOP_SECURITY_AUTHORIZATION,
false);
+ UserGroupInformation.setConfiguration(serverConf);
}
+
+ final HttpServer server = createServer(isSpnego);
+ // get server port
+ final String authority =
NetUtils.getHostPortString(server.getConnectorAddress(0));
+
+ String keytabFilePath = KEYTAB_FILE.getAbsolutePath();
+
+ UserGroupInformation clientUGI = UserGroupInformation.
+ loginUserFromKeytabAndReturnUGI(clientPrincipal, keytabFilePath);
+ try {
+ clientUGI.doAs(new PrivilegedExceptionAction<Void>() {
+ @Override public Void run() throws Exception {
+ // client command line
+ TestLogLevel.this.getLevel(authority);
+ TestLogLevel.this.setLevel(authority, newLevel);
+ return null;
+ }
+ });
+ } finally {
+ clientUGI.logoutUserFromKeytab();
+ server.stop();
+ }
+
+ // restore log level
+ GenericTestUtils.setLogLevel(log, oldLevel);
+ }
+
+ /**
+ * Run LogLevel command line to start a client to get log level of this test
+ * class.
+ *
+ * @param authority daemon's web UI address
+ * @throws Exception if unable to connect
+ */
+ private void getLevel(String authority) throws Exception {
+ String[] getLevelArgs = {"-getlevel", authority, logName};
+ CLI cli = new CLI(clientConf);
+ cli.run(getLevelArgs);
+ }
+
+ /**
+ * Run LogLevel command line to start a client to set log level of this test
+ * class to debug.
+ *
+ * @param authority daemon's web UI address
+ * @throws Exception if unable to run or log level does not change as
expected
+ */
+ private void setLevel(String authority, String newLevel)
+ throws Exception {
+ String[] setLevelArgs = {"-setlevel", authority, logName, newLevel};
+ CLI cli = new CLI(clientConf);
+ cli.run(setLevelArgs);
+
+ assertEquals("new level not equal to expected: ", newLevel.toUpperCase(),
+ log.getEffectiveLevel().toString());
+ }
+
+ /**
+ * Test setting log level to "Info".
+ *
+ * @throws Exception if client can't set log level to INFO.
+ */
+ @Test(timeout=60000)
+ public void testInfoLogLevel() throws Exception {
+ testDynamicLogLevel(true, "INFO");
+ }
+
+ /**
+ * Test setting log level to "Error".
+ *
+ * @throws Exception if client can't set log level to ERROR.
+ */
+ @Test(timeout=60000)
+ public void testErrorLogLevel() throws Exception {
+ testDynamicLogLevel(true, "ERROR");
+ }
+
+ /**
+ * Server runs HTTP, no SPNEGO.
+ *
+ * @throws Exception if http client can't access http server.
+ */
+ @Test(timeout=60000)
+ public void testLogLevelByHttp() throws Exception {
+ testDynamicLogLevel(false);
+ }
+
+ /**
+ * Server runs HTTP + SPNEGO.
+ *
+ * @throws Exception if http client can't access http server.
+ */
+ @Test(timeout=60000)
+ public void testLogLevelByHttpWithSpnego() throws Exception {
+ testDynamicLogLevel(true);
}
}