/* * Copyright 2013-2014 Splunk, Inc. * * Licensed 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. */ import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; import com.splunk.*; import org.junit.Assert; import org.slf4j.*; import java.io.*; import java.nio.charset.Charset; import java.nio.file.Files; import java.util.*; import java.util.logging.LogManager; import java.util.regex.Matcher; import java.util.regex.Pattern; public class TestUtil { private static final ServiceArgs serviceArgs = new ServiceArgs(); private static Service service; private static final String httpEventCollectorTokenEndpointPath = "/services/data/inputs/http"; /** * read splunk host info from .splunkrc file */ private static void getSplunkHostInfo() throws IOException { if (serviceArgs.isEmpty()) { //set default value serviceArgs.setUsername("admin"); serviceArgs.setPassword("changeme"); serviceArgs.setHost("localhost"); serviceArgs.setPort(8089); serviceArgs.setScheme("https"); //update serviceArgs with customer splunk host info String splunkhostfile = System.getProperty("user.home") + File.separator + ".splunkrc"; List<String> lines = Files.readAllLines(new File(splunkhostfile).toPath(), Charset.defaultCharset()); for (String line : lines) { if (line.toLowerCase().contains("host=")) { serviceArgs.setHost(line.split("=")[1]); } if (line.toLowerCase().contains("admin=")) { serviceArgs.setUsername(line.split("=")[1]); } if (line.toLowerCase().contains("password=")) { serviceArgs.setPassword(line.split("=")[1]); } if (line.toLowerCase().contains("scheme=")) { serviceArgs.setScheme(line.split("=")[1]); } if (line.toLowerCase().contains("port=")) { serviceArgs.setPort(Integer.parseInt(line.split("=")[1])); } } } // Use TLSv1 intead of SSLv3 serviceArgs.setSSLSecurityProtocol(SSLSecurityProtocol.TLSv1); } public static void resetConnection() { service = null; } public static Service connectToSplunk() throws IOException { int retry = 0; while (true) { try { if (service == null) { getSplunkHostInfo(); service = Service.connect(serviceArgs); service.login(); } return service; } catch (IOException ex) { retry++; if (retry > 5) throw ex; } } } public static void createIndex(String indexName) throws Exception { connectToSplunk(); IndexCollection indexes = service.getIndexes(); if (indexes.containsKey(indexName)) { Index index = indexes.get(indexName); indexes.remove(indexName); } indexes.create(indexName); } /** * create http event collector token */ public static String createHttpEventCollectorToken(String httpEventCollectorName) throws Exception { connectToSplunk(); //enable logging endpoint enableHttpEventCollector(); //create an httpEventCollector Map args = new HashMap(); args.put("name", httpEventCollectorName); args.put("description", "test http event collector"); deleteHttpEventCollectorToken(httpEventCollectorName); Thread.sleep(500); ResponseMessage msg = service.post(httpEventCollectorTokenEndpointPath, args); assert msg.getStatus() == 201; //get httpEventCollector token args = new HashMap(); ResponseMessage response = service.get(httpEventCollectorTokenEndpointPath + "/" + httpEventCollectorName, args); BufferedReader reader = new BufferedReader(new InputStreamReader(response.getContent(), "UTF-8")); String token = ""; while (true) { String line = reader.readLine(); if (line == null) break; if (line.contains("name=\"token\"")) { token = line.split(">")[1]; token = token.split("<")[0]; break; } } reader.close(); if (token.isEmpty()) { Assert.fail("no httpEventCollector token is created"); } return token; } /** * delete http event collector token */ public static void deleteHttpEventCollectorToken(String httpEventCollectorName) throws Exception { connectToSplunk(); try { ResponseMessage response = service.get(httpEventCollectorTokenEndpointPath + "/" + httpEventCollectorName); if (response.getStatus() == 200) { response = service.delete(httpEventCollectorTokenEndpointPath + "/" + httpEventCollectorName); assert response.getStatus() == 200; } } catch (com.splunk.HttpException e) { if (e.getStatus() != 404) throw e; } } /** * disable http event collector feature */ public static void disableHttpEventCollector() throws IOException { connectToSplunk(); //disable logging endpoint Map args = new HashMap(); args.put("disabled", 1); ResponseMessage response = service.post("/servicesNS/admin/search/data/inputs/http/http", args); assert response.getStatus() == 200; } /** * enable http event collector feature */ public static void enableHttpEventCollector() throws IOException { connectToSplunk(); //enable logging endpoint Map args = new HashMap(); args.put("disabled", 0); ResponseMessage response = service.post("/servicesNS/admin/search/data/inputs/http/http", args); assert response.getStatus() == 200; } /** * disable http event collector token */ public static void disableHttpEventCollector(String httpEventCollectorName) throws IOException { connectToSplunk(); Map args = new HashMap(); args.put("disabled", 1); ResponseMessage response = service.post(httpEventCollectorTokenEndpointPath + "/" + httpEventCollectorName, args); assert response.getStatus() == 200; } /** * modify the config file with the generated token, and configured splunk host, * read the template from configFileTemplate, and create the updated configfile to configFile */ public static String updateConfigFile(String configFileTemplate, String configFile, HashMap<String, String> userInputs) throws IOException { getSplunkHostInfo(); String configFileDir = TestUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath(); List<String> lines = Files.readAllLines(new File(configFileDir, configFileTemplate).toPath(), Charset.defaultCharset()); for (int i = 0; i < lines.size(); i++) { if (lines.get(i).contains("%host%")) { lines.set(i, lines.get(i).replace("%host%", serviceArgs.host)); } if (lines.get(i).contains("%port%")) { lines.set(i, lines.get(i).replace("%port%", serviceArgs.port.toString())); } if (lines.get(i).contains("%scheme%")) { lines.set(i, lines.get(i).replace("%scheme%", serviceArgs.scheme)); } String match = FindUserInputConfiguration(lines.get(i)); if (!match.isEmpty()) { if (userInputs.keySet().contains(match)) lines.set(i, lines.get(i).replace("%" + match + "%", userInputs.get(match))); else lines.set(i, ""); } } String configFilePath = new File(configFileDir, configFile).getPath(); FileWriter fw = new FileWriter(configFilePath); for (String line : lines) { if (!line.isEmpty()) { fw.write(line); fw.write(System.getProperty("line.separator")); } } fw.flush(); fw.close(); return configFilePath; } private static String FindUserInputConfiguration(String line) { String pattern = "%.*%"; Pattern r = Pattern.compile(pattern); Matcher m = r.matcher(line); if (m.find()) { return m.group(0).substring(1, m.group(0).length() - 1); } else return ""; } /* create log4j2.xml and force log4j2 context manager to reload the configurations, return context and using this context to retrieve logger instead of using LogManager */ public static org.apache.logging.log4j.core.LoggerContext resetLog4j2Configuration(String configFileTemplate, String configFile, HashMap<String, String> userInputs) throws IOException, JoranException { String configFilePath = updateConfigFile(configFileTemplate, configFile, userInputs); org.apache.logging.log4j.core.LoggerContext context = new org.apache.logging.log4j.core.LoggerContext(userInputs.get("user_logger_name")); context.reconfigure(); context.updateLoggers(); return context; } /* create logback.xml and force logback manager to reload the configurations */ public static void resetLogbackConfiguration(String configFileTemplate, String configFile, HashMap<String, String> userInputs) throws IOException, JoranException { String configFilePath = updateConfigFile(configFileTemplate, configFile, userInputs); //force the Logback factory to reload the configuration file JoranConfigurator jc = new JoranConfigurator(); LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); jc.setContext(context); context.reset(); jc.doConfigure(configFilePath); } /* create logging.property and force java logging manager to reload the configurations */ public static void resetJavaLoggingConfiguration(String configFileTemplate, String configFile, HashMap<String, String> userInputs) throws IOException, JoranException { String configFilePath = updateConfigFile(configFileTemplate, configFile, userInputs); FileInputStream configFileStream = new FileInputStream(configFilePath); LogManager.getLogManager().readConfiguration(configFileStream); configFileStream.close(); } public static void verifyOneAndOnlyOneEventSentToSplunk(String msg) throws IOException { connectToSplunk(); long startTime = System.currentTimeMillis(); int eventCount = 0; InputStream resultsStream = null; ResultsReaderXml resultsReader = null; while (System.currentTimeMillis() - startTime < 30 * 1000)/*wait for up to 30s*/ { resultsStream = service.oneshotSearch("search " + msg); resultsReader = new ResultsReaderXml(resultsStream); //verify has one and only one record return for (Event event : resultsReader) { eventCount++; System.out.println("---------------"); System.out.println(event.getSegmentedRaw()); } if (eventCount > 0) break; } resultsReader.close(); resultsStream.close(); Assert.assertTrue(eventCount == 1); } public static void verifyNoEventSentToSplunk(List<String> msgs) throws IOException { connectToSplunk(); String searchstr = org.apache.commons.lang3.StringUtils.join(msgs, "\" OR \""); searchstr = "\"" + searchstr + "\""; long startTime = System.currentTimeMillis(); int eventCount = 0; InputStream resultsStream = null; ResultsReaderXml resultsReader = null; while (System.currentTimeMillis() - startTime < 10 * 1000)/*wait for up to 30s*/ { resultsStream = service.oneshotSearch("search " + searchstr); resultsReader = new ResultsReaderXml(resultsStream); //verify has one and only one record return for (Event event : resultsReader) { eventCount++; System.out.println("------verify no events---------"); System.out.println(event.getSegmentedRaw()); } if (eventCount > 0) break; } resultsReader.close(); resultsStream.close(); Assert.assertTrue(eventCount == 0); } /* verify each of the message in msgs appeared and appeared only once in splunk */ public static void verifyEventsSentToSplunk(List<String> msgs) throws IOException { connectToSplunk(); for (String msg : msgs) { long startTime = System.currentTimeMillis(); int eventCount = 0; InputStream resultsStream = null; ResultsReaderXml resultsReader = null; while (System.currentTimeMillis() - startTime < 30 * 1000)/*wait for up to 30s*/ { resultsStream = service.oneshotSearch("search " + msg); resultsReader = new ResultsReaderXml(resultsStream); //verify has one and only one record return for (Event event : resultsReader) { eventCount++; System.out.println("------verify has events---------"); System.out.println(event.getSegmentedRaw()); } if (eventCount > 0) break; } resultsReader.close(); resultsStream.close(); Assert.assertTrue(eventCount == 1); } } public static void verifyEventsSentInOrder(String prefix, int totalEventsCount, String index) throws IOException { connectToSplunk(); long startTime = System.currentTimeMillis(); InputStream resultsStream = null; ResultsReaderXml resultsReader = null; List<String> results = new ArrayList<String>(); while (System.currentTimeMillis() - startTime < 100 * 1000)/*wait for up to 30s*/ { results.clear(); String searchstr = "search index=" + index; resultsStream = service.oneshotSearch(searchstr, new Args("count", 0)); resultsReader = new ResultsReaderXml(resultsStream); for (Event event : resultsReader) { results.add(event.getSegmentedRaw()); } if (results.size() == totalEventsCount) break; } resultsReader.close(); resultsStream.close(); assert (results.size() == totalEventsCount) : String.format("expect: %d, actual: %d", totalEventsCount, results.size()); //verify events record is in correct order for (int i = 0; i < totalEventsCount; i++) { String expect = String.format("%s %s", prefix, totalEventsCount - 1 - i); assert results.get(i).contains(expect) : String.format("expect: %s, actual: %s", expect, results.get(i)); } } }