/**
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.hadoop.yarn.server.applicationhistoryservice.metrics.loadsimulator.jmetertest.jmetertest;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.yarn.server.applicationhistoryservice.metrics.loadsimulator.MetricsLoadSimulator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class AMSJMeterLoadTest {
private final static Logger LOG = LoggerFactory.getLogger(AMSJMeterLoadTest.class);
private static String PROPERTIES_FILE = "loadsimulator/ams-jmeter.properties";
private ScheduledExecutorService scheduledExecutorService = null;
private List<AppGetMetric> appGetMetrics;
private Properties amsJmeterProperties = null;
public AMSJMeterLoadTest(Map<String, String> args) {
String testType = args.get("type");
String userDefinedPropertiesFile = args.get("amsJmeterPropertiesFile");
if (null == userDefinedPropertiesFile || userDefinedPropertiesFile.isEmpty()) {
this.amsJmeterProperties = readProperties(PROPERTIES_FILE);
} else {
this.amsJmeterProperties = readProperties(userDefinedPropertiesFile);
}
if ("U".equals(testType)) { //GET metrics simulator
int numInstances = Integer.valueOf(amsJmeterProperties.getProperty("num-ui-instances"));
this.scheduledExecutorService = Executors.newScheduledThreadPool(numInstances);
this.appGetMetrics = initializeGetMetricsPayload(amsJmeterProperties);
this.runTest(numInstances);
} else { //PUT Metrics simulator
Map<String, String> mapArgs = new HashMap<String, String>();
mapArgs.put("hostName", (args.get("host-prefix") != null) ? args.get("host-prefix") : amsJmeterProperties.getProperty("host-prefix"));
mapArgs.put("minHostIndex", (args.get("min-host-index") != null) ? args.get("min-host-index") : amsJmeterProperties.getProperty("min-host-index"));
mapArgs.put("numberOfHosts", (args.get("num-hosts") != null) ? args.get("num-hosts") : amsJmeterProperties.getProperty("num-hosts"));
mapArgs.put("metricsHostName", (args.get("ams-host-port") != null) ? args.get("ams-host-port") : amsJmeterProperties.getProperty("ams-host-port"));
mapArgs.put("collectInterval", (args.get("collection-interval") != null) ? args.get("collection-interval") : amsJmeterProperties.getProperty("collection-interval"));
mapArgs.put("sendInterval", (args.get("send-interval") != null) ? args.get("send-interval") : amsJmeterProperties.getProperty("send-interval"));
mapArgs.put("master", (args.get("create-master") != null) ? args.get("create-master") : amsJmeterProperties.getProperty("create-master"));
System.out.println("AMS Load Simulation Parameters : " + mapArgs);
MetricsLoadSimulator.startTest(mapArgs);
}
}
public static Properties readProperties(String propertiesFile) {
try {
Properties properties = new Properties();
InputStream inputStream = ClassLoader.getSystemResourceAsStream(propertiesFile);
if (inputStream == null) {
inputStream = new FileInputStream(propertiesFile);
}
properties.load(inputStream);
return properties;
} catch (IOException ioEx) {
LOG.error("Error reading properties file for jmeter");
return null;
}
}
private static List<GetMetricRequestInfo> readMetricsFromFile(String app) {
InputStream input = null;
List<GetMetricRequestInfo> metricList = new ArrayList<>();
String fileName = "ui_metrics_def/" + app + ".dat";
try {
input = ClassLoader.getSystemResourceAsStream(fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line;
List<String> metrics = new ArrayList<>();
while ((line = reader.readLine()) != null) {
if (line.startsWith("|")) {
boolean needsTimestamps = line.contains("startTime");
boolean needsHost = line.contains("hostname");
metricList.add(new GetMetricRequestInfo(metrics, needsTimestamps, needsHost));
metrics.clear();
} else {
metrics.add(line);
}
}
return metricList;
} catch (IOException e) {
LOG.error("Cannot read file " + fileName + " for appID " + app, e);
} finally {
if (input != null) {
try {
input.close();
} catch (IOException ex) {
}
}
}
return null;
}
private static List<AppGetMetric> initializeGetMetricsPayload(Properties amsJmeterProperties) {
List<AppGetMetric> appGetMetrics = new ArrayList<AppGetMetric>();
String appsToTest = amsJmeterProperties.getProperty("apps-to-test");
String[] apps;
if (appsToTest != null && !appsToTest.isEmpty()) {
apps = StringUtils.split(appsToTest, ",");
} else {
apps = new String[JmeterTestPlanTask.ClientApp.values().length];
int ctr = 0;
for (JmeterTestPlanTask.ClientApp app : JmeterTestPlanTask.ClientApp.values())
apps[ctr++] = app.getId();
}
for (String app : apps) {
int interval = Integer.valueOf(amsJmeterProperties.getProperty("get-interval"));
String intervalString = amsJmeterProperties.getProperty(app + "-get-interval");
if (intervalString != null && !intervalString.isEmpty()) {
interval = Integer.valueOf(intervalString);
}
appGetMetrics.add(new AppGetMetric(readMetricsFromFile(app), interval, app));
}
return appGetMetrics;
}
public void runTest(int numInstances) {
int appRefreshRate = Integer.valueOf(amsJmeterProperties.getProperty("app-refresh-rate"));
for (int i = 0; i < numInstances; i++) {
ScheduledFuture future = scheduledExecutorService.scheduleAtFixedRate(new JmeterTestPlanTask(appGetMetrics,
amsJmeterProperties), 0, appRefreshRate, TimeUnit.MILLISECONDS);
}
}
/**
* Sample Usage:
* java -cp "lib/*":ambari-metrics-timelineservice-2.1.1.0.jar org.apache.hadoop.yarn.server.applicationhistoryservice
* .metrics.loadsimulator.jmeter.AMSJMeterLoadTest
* -t UI -p ambari-metrics-timelineservice/src/main/resources/jmeter/ams-jmeter.properties
*/
public static void main(String[] args) {
Map<String, String> mapArgs = parseArgs(args);
new AMSJMeterLoadTest(mapArgs);
}
private static Map<String, String> parseArgs(String[] args) {
Map<String, String> mapProps = new HashMap<String, String>();
if (args.length == 0) {
printUsage();
throw new RuntimeException("Unexpected argument, See usage message.");
} else {
for (int i = 0; i < args.length; i += 2) {
String arg = args[i];
mapProps.put(arg.substring(1), args[i+1]);
}
}
return mapProps;
}
public static void printUsage() {
System.err.println("Usage: java AMSJmeterLoadTest [OPTIONS]");
System.err.println("Options: ");
System.err.println("[--t type (S=>Sink/U=>UI)] [-ams-host-port localhost:6188] [-min-host-index 2] [-host-prefix TestHost.] [-num-hosts 2] " +
"[-create-master true] [-collection-interval 10000 ] [-send-interval 60000 ] [-p amsJmeterPropertiesFile (Optional)]");
}
}