package com.intuit.tank.standalone.agent;
/*
* #%L
* Agent Standalone
* %%
* Copyright (C) 2011 - 2015 Intuit Inc.
* %%
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* #L%
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.intuit.tank.AgentServiceClient;
import com.intuit.tank.harness.HostInfo;
import com.intuit.tank.vm.agent.messages.AgentAvailability;
import com.intuit.tank.vm.agent.messages.AgentAvailabilityStatus;
import com.intuit.tank.vm.agent.messages.StandaloneAgentRequest;
public class StandaloneAgentStartup implements Runnable {
private static Logger LOG = LogManager.getLogger(StandaloneAgentStartup.class);
public static final String SERVICE_RELATIVE_PATH = "/rest/v1/agent-service";
private static String API_HARNESS_COMMAND = "./start_wats.sh";
public static final String METHOD_SETTINGS = "/settings";
public static final String METHOD_SUPPORT = "/supportFiles";
private static final long PING_TIME = 1000 * 60 * 5;// five minutes
private String controllerBase;
private AgentAvailability currentAvailability;
private AgentServiceClient agentClient;
private String instanceId;
private String hostname;
private int capacity = 4000;
@Override
public void run() {
CommandListener.startHttpServer(CommandListener.PORT, this);
agentClient = new AgentServiceClient(controllerBase);
if (hostname != null) {
instanceId = hostname;
} else {
instanceId = new HostInfo().getPublicIp();
}
currentAvailability = new AgentAvailability(instanceId, getInstanceUrl(), capacity,
AgentAvailabilityStatus.AVAILABLE);
startPinger();
}
public void startTest(final StandaloneAgentRequest request) {
Thread t = new Thread(new Runnable() {
public void run() {
try {
currentAvailability.setAvailabilityStatus(AgentAvailabilityStatus.DELEGATING);
sendAvailability();
LOG.info("Starting up: ControllerBaseUrl=" + controllerBase);
URL url = new URL(controllerBase + SERVICE_RELATIVE_PATH + METHOD_SETTINGS);
LOG.info("Starting up: making call to tank service url to get settings.xml "
+ url.toExternalForm());
InputStream settingsStream = url.openStream();
try {
String settings = IOUtils.toString(settingsStream);
FileUtils.writeStringToFile(new File("settings.xml"), settings);
LOG.info("got settings file...");
} finally {
IOUtils.closeQuietly(settingsStream);
}
url = new URL(controllerBase + SERVICE_RELATIVE_PATH + METHOD_SUPPORT);
LOG.info("Making call to tank service url to get support files " + url.toExternalForm());
ZipInputStream zip = new ZipInputStream(url.openStream());
try {
ZipEntry entry = zip.getNextEntry();
while (entry != null) {
String name = entry.getName();
LOG.info("Got file from controller: " + name);
File f = new File(name);
FileOutputStream fout = FileUtils.openOutputStream(f);
try {
IOUtils.copy(zip, fout);
} finally {
IOUtils.closeQuietly(fout);
}
entry = zip.getNextEntry();
}
} finally {
IOUtils.closeQuietly(zip);
}
// now start the harness
String cmd = API_HARNESS_COMMAND + " -http=" + controllerBase + " -jobId=" + request.getJobId()
+ " -stopBehavior=" + request.getStopBehavior();
LOG.info("Starting apiharness with command: " + cmd);
currentAvailability.setAvailabilityStatus(AgentAvailabilityStatus.RUNNING_JOB);
sendAvailability();
Process exec = Runtime.getRuntime().exec(cmd);
exec.waitFor();
currentAvailability.setAvailabilityStatus(AgentAvailabilityStatus.AVAILABLE);
sendAvailability();
//
} catch (Exception e) {
LOG.error("Error in AgentStartup " + e, e);
currentAvailability.setAvailabilityStatus(AgentAvailabilityStatus.AVAILABLE);
sendAvailability();
}
}
});
t.start();
}
private String getInstanceUrl() {
if (hostname == null) {
hostname = new HostInfo().getPublicIp();
if (hostname.equals(HostInfo.UNKNOWN)) {
LOG.error("Cannot determine local hostname or ip please specify on the caomandline.");
System.err.println("Cannot determine local hostname or ip please specify on the caomandline.");
usage();
System.exit(1);
}
}
return "http://" + hostname + ":" + CommandListener.PORT;
}
private void startPinger() {
Thread t = new Thread(new Runnable() {
public void run() {
while (true) {
try {
sendAvailability();
} catch (Exception e1) {
LOG.warn("Error sending Availability: " + e1, e1);
}
try {
Thread.sleep(PING_TIME);
} catch (InterruptedException e) {
LOG.warn("Interrupted during sleep.", e);
}
}
}
});
t.setDaemon(true);
t.start();
}
private void sendAvailability() {
// create new availability as a copy of the original
AgentAvailability availability = new AgentAvailability(currentAvailability.getInstanceId(),
currentAvailability.getInstanceUrl(), currentAvailability.getCapacity(),
currentAvailability.getAvailabilityStatus());
LOG.info("Sending availaability: " + ToStringBuilder.reflectionToString(availability));
agentClient.standaloneAgentAvailable(availability);
}
public static void main(String[] args) {
StandaloneAgentStartup agentStartup = new StandaloneAgentStartup();
for (int iter = 0; iter < args.length; ++iter) {
String argument = args[iter];
String[] values = argument.split("=");
if (values[0].equalsIgnoreCase("-controller")) {
if (values.length < 2) {
usage();
return;
}
agentStartup.controllerBase = values[1];
continue;
} else if (values[0].equalsIgnoreCase("-host")) {
if (values.length < 2) {
usage();
return;
}
agentStartup.hostname = values[1];
continue;
} else if (values[0].equalsIgnoreCase("-capacity")) {
if (values.length < 2) {
usage();
return;
}
try {
agentStartup.capacity = Integer.parseInt(values[1]);
} catch (NumberFormatException e) {
LOG.error("Error parsing capacity " + values[1] + " Capacity must be an integer.");
System.out.println("Error parsing capacity " + values[1] + " Capacity must be an integer.");
usage();
return;
}
continue;
}
}
if (StringUtils.isBlank(agentStartup.controllerBase)) {
usage();
System.exit(1);
}
agentStartup.run();
}
/**
* Display usage error text
*/
private static void usage() {
System.out.println("TAnk Standalone Agent Startup Usage:");
System.out
.println("java -cp standaloneagent-startup-pkg-1.0-all.jar com/intuit/tank/agent/StandaloneAgentStartup <options>");
System.out.println("-controller=<controller_base_url>: The url of the controller to get test info from.");
System.out
.println("-host=<agent ip or host>: optional. only need if agent cannot determine correct ip. The ip or dns name of this agent.");
System.out
.println("-capacity=<integer>: optional. The number of users this agent can simulate. Default 4000.");
}
}