/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package loadTest.loadTestLib;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.FileUtils;
import org.pieShare.pieShareApp.service.PieShareService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
/**
*
* @author richy
*/
public class LUtil {
private static boolean runInDockerCluster = false;
private static boolean dockerError;
private static int doneDockers;
private static boolean useDocker = false;
private HashMap<String, Integer> startedClusterContainer = new HashMap<>();
private HashMap<String, List<String>> runningContainers = new HashMap<>();
private List<Process> slaves = new ArrayList<>();
public static boolean UseDocker() {
return useDocker;
}
public static String getWorkingDir() {
return "loadTest/workingDir";
}
public static String getTmpDir() {
return "loadTest/tmpDir";
}
public static String getConfigDir() {
return "loadTest/loadTestConfig";
}
public static void setUpEnviroment() {
System.setProperty("java.net.preferIPv4Stack", "true");
System.setProperty("jgroups.logging.log_factory_class", "org.pieShare.pieTools.piePlate.service.cluster.jgroupsCluster.JGroupsLoggerFactory");
}
public void performTearDown(ApplicationContext context) throws Exception {
int responseCode = -1;
if (runInDockerCluster) {
try {
for (Entry<String, List<String>> node : runningContainers.entrySet()) {
for (String container : node.getValue()) {
String url = String.format("%s/containers/%s/stop?t=0", node.getKey(), container);
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
responseCode = con.getResponseCode();
con.disconnect();
}
}
if (responseCode != 204) {
dockerError = true;
}
} catch (MalformedURLException ex) {
dockerError = true;
} catch (FileNotFoundException ex) {
dockerError = true;
} catch (IOException ex) {
dockerError = true;
}
if (dockerError) {
throw new Exception("Error closing docker containers!");
}
}
/*PieShareService service = context.getBean(PieShareService.class);
service.stop();
System.out.println("Services stoped!");
ConfigurableApplicationContext con = (ConfigurableApplicationContext)context;
con.close();*/
slaves.forEach(s -> s.destroy());
}
public void performTearDownDelete() throws Exception {
FileUtils.deleteDirectory(new File(getWorkingDir()));
FileUtils.deleteDirectory(new File(getTmpDir()));
FileUtils.deleteDirectory(new File(getConfigDir()));
}
public static List<LoadTestConfigModel> readJSONConfig() throws IOException {
InputStream in = LUtil.class.getClassLoader().getResourceAsStream("loadTestConfig.json");
ObjectMapper mapper = new ObjectMapper();
List<LoadTestConfigModel> myObjects = mapper.readValue(in, mapper.getTypeFactory().constructCollectionType(List.class, LoadTestConfigModel.class));
return myObjects;
}
public static void setUpResultFile() throws IOException {
FileWriter writer = new FileWriter("loadTestResults.csv");
writer.write("NodeCount,FileCount,FileSize,ResultTime\n");
writer.flush();
writer.close();
}
public static void writeCSVResult(LoadTestConfigModel model, long resTime) throws IOException {
FileWriter writer = new FileWriter("loadTestResults.csv", true);
writer.append(String.valueOf(model.getNodeCount()));
writer.append(",");
writer.append(String.valueOf(model.getFileCount()));
writer.append(",");
writer.append(String.valueOf(model.getFileSize()));
writer.append(",");
writer.append(String.valueOf(resTime));
writer.append("\n");
writer.flush();
writer.close();
}
public static boolean IsMaster() {
String ltType = System.getenv("LTTYPE");
if (ltType == null) {
return true;
}
if (ltType.equals("master")) {
return true;
}
return false;
}
public static HashMap<String, Integer> getDockerNodes() {
HashMap<String, Integer> dockerNodes = new HashMap<>();
dockerNodes.put("http://127.0.0.1:2375", 5);
//dockerNodes.put("192.168.0.16:2375", 5);
return dockerNodes;
}
public static void runInDockerCluster() {
runInDockerCluster = true;
}
public static boolean startDockerBuild() throws IOException, InterruptedException {
if (useDocker) {
if (runInDockerCluster) {
HashMap<String, Integer> dockerNodes = getDockerNodes();
String dockerTar = LUtil.class.getClassLoader().getResource("docker/loadTest.tar").toString().substring(5);
ExecutorService exec = Executors.newFixedThreadPool(dockerNodes.size());
dockerError = false;
doneDockers = 0;
for (Entry<String, Integer> entry : dockerNodes.entrySet()) {
exec.submit(new Runnable() {
@Override
public void run() {
try {
String url = entry.getKey() + "/images/vauvenal5/loadtest";
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("DELETE");
con.setRequestProperty("force", "true");
int responseCode = con.getResponseCode();
con.disconnect();
url = entry.getKey() + "/build?t=vauvenal5/loadtest&dockerfile=./loadTest/Dockerfile";
obj = new URL(url);
con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-type", "application/tar");
con.setDoOutput(true);
File file = new File(dockerTar);
FileInputStream fileStr = new FileInputStream(file);
byte[] b = new byte[(int) file.length()];
fileStr.read(b);
con.getOutputStream().write(b);
con.getOutputStream().flush();
con.getOutputStream().close();
responseCode = con.getResponseCode();
if (responseCode != 200) {
dockerError = true;
}
String msg = "";
do {
Thread.sleep(5000);
msg = "";
url = entry.getKey() + "/images/json";
obj = new URL(url);
HttpURLConnection con2 = (HttpURLConnection) obj.openConnection();
con2.setRequestMethod("GET");
responseCode = con2.getResponseCode();
BufferedReader in = new BufferedReader(new InputStreamReader(con2.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
msg += line;
}
con2.disconnect();
} while (!msg.contains("vauvenal5/loadtest"));
con.disconnect();
doneDockers++;
} catch (MalformedURLException ex) {
dockerError = true;
} catch (FileNotFoundException ex) {
dockerError = true;
} catch (IOException ex) {
dockerError = true;
} catch (InterruptedException ex) {
dockerError = true;
}
}
});
}
while (doneDockers < dockerNodes.size()) {
Thread.sleep(5000);
}
return !dockerError;
}
//get the path and substring the 'file:' from the URI
String dockerfile = LUtil.class.getClassLoader().getResource("docker/loadTest").toString().substring(5);
ProcessBuilder processBuilder = new ProcessBuilder("docker", "rmi", "-f", "vauvenal5/loadtest");
processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process docker = processBuilder.start();
docker.waitFor();
processBuilder = new ProcessBuilder("docker", "build", "-t", "vauvenal5/loadtest", dockerfile);
processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process proc = processBuilder.start();
return proc.waitFor() == 0;
}
return true;
}
private Entry<String, Integer> getLowestDockerHost() {
HashMap<String, Integer> dockerNodes = getDockerNodes();
Entry<String, Integer> lowest = null;
if (this.startedClusterContainer.size() < dockerNodes.size()) {
for (Entry<String, Integer> entry : dockerNodes.entrySet()) {
if (!this.startedClusterContainer.containsKey(entry.getKey())) {
return new AbstractMap.SimpleEntry<>(entry.getKey(), 0);
}
}
}
for (Entry<String, Integer> entry : startedClusterContainer.entrySet()) {
if (entry.getValue() < dockerNodes.get(entry.getKey())) {
if (lowest == null) {
lowest = entry;
} else {
if (lowest.getValue() > entry.getValue()) {
lowest = entry;
}
}
}
}
return lowest;
}
public boolean startDockerSlave(LoadTestConfigModel ltModel) throws InterruptedException, IOException {
String fileCount = String.valueOf(ltModel.getFileCount());
if (runInDockerCluster) {
HashMap<String, Integer> dockerNodes = getDockerNodes();
Entry<String, Integer> entry = this.getLowestDockerHost();
startedClusterContainer.put(entry.getKey(), entry.getValue() + 1);
String dockerCommand = "{"
+ "\"Hostname\":\"\","
+ "\"User\":\"\","
+ "\"Entrypoint\":[\"/bin/bash\",\"/pieShare/pieShareAppIntegrationTests/src/test/resources/docker/internal.sh\"],"
+ "\"Cmd\":[\"slave\",\"" + fileCount.toString() + "\"],"
+ "\"Memory\":0,"
+ "\"MemorySwap\":0,"
+ "\"AttachStdin\":false,"
+ "\"AttachStdout\":false,"
+ "\"AttachStderr\":false,"
+ "\"PortSpecs\":null,"
+ "\"Privileged\": false,"
+ "\"Tty\":false,"
+ "\"OpenStdin\":false,"
+ "\"StdinOnce\":false,"
+ "\"Env\":null,"
+ "\"Dns\":null,"
+ "\"Image\":\"vauvenal5/loadtest\","
+ "\"Volumes\":{},"
+ "\"VolumesFrom\":\"\","
+ "\"WorkingDir\":\"\"}";
String url = entry.getKey() + "/containers/create";
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-type", "application/json");
con.setDoOutput(true);
con.getOutputStream().write(dockerCommand.getBytes());
con.getOutputStream().flush();
con.getOutputStream().close();
int responseCode = con.getResponseCode();
if (responseCode != 201) {
return false;
}
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String line = null;
String msg = "";
while ((line = in.readLine()) != null) {
msg += line;
}
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(msg);
String containerId = node.get("Id").asText();
con.disconnect();
url = entry.getKey() + "/containers/" + containerId + "/start";
obj = new URL(url);
con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-type", "application/json");
responseCode = con.getResponseCode();
if (responseCode != 204) {
return false;
}
if (!this.runningContainers.containsKey(entry.getKey())) {
this.runningContainers.put(entry.getKey(), new ArrayList<>());
}
this.runningContainers.get(entry.getKey()).add(containerId);
return true;
}
ProcessBuilder processBuilder = new ProcessBuilder("docker", "run", "vauvenal5/loadtest", "slave", fileCount);
Process proc = processBuilder.start();
this.slaves.add(proc);
return true;
}
}