package org.arquillian.cube.docker.impl.util;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import java.util.regex.Pattern;
public class DockerMachine extends AbstractCliInternetAddressResolver {
public static final String DOCKER_MACHINE_EXEC = "docker-machine";
private static final Pattern IP_PATTERN = Pattern.compile("(?:\\d{1,3}\\.){3}\\d{1,3}");
private static Logger log = Logger.getLogger(DockerMachine.class.getName());
private String machineName;
private boolean manuallyStarted = false;
public DockerMachine(CommandLineExecutor commandLineExecutor) {
super(commandLineExecutor);
}
@Override
protected String[] getCommandArguments(String cliPathExec) {
if (machineName == null) {
throw new IllegalArgumentException("Machine Name cannot be null");
}
return new String[] {createDockerMachineCommand(cliPathExec), "ip", machineName};
}
@Override
protected Pattern getIpPattern() {
return IP_PATTERN;
}
public void setMachineName(String machineName) {
this.machineName = machineName;
}
public boolean isManuallyStarted() {
return manuallyStarted;
}
/**
* Starts given docker machine.
*
* @param cliPathExec
* location of docker-machine or null if it is on PATH.
* @param machineName
* to be started.
*/
public void startDockerMachine(String cliPathExec, String machineName) {
commandLineExecutor.execCommand(createDockerMachineCommand(cliPathExec), "start", machineName);
this.manuallyStarted = true;
}
/**
* Starts given docker machine.
*
* @param machineName
* to be started.
*/
public void startDockerMachine(String machineName) {
startDockerMachine(null, machineName);
}
public void stopDockerMachine(String cliPathExec, String machineName) {
commandLineExecutor.execCommand(createDockerMachineCommand(cliPathExec), "stop", machineName);
this.manuallyStarted = false;
}
public void stopDockerMachine(String machineName) {
stopDockerMachine(null, machineName);
}
/**
* Checks if Docker Machine is installed by running docker-machine and inspect the result.
*
* @param cliPathExec
* location of docker-machine or null if it is on PATH.
*
* @return true if it is installed, false otherwise.
*/
public boolean isDockerMachineInstalled(String cliPathExec) {
try {
commandLineExecutor.execCommand(createDockerMachineCommand(cliPathExec));
return true;
} catch (Exception e) {
return false;
}
}
/**
* Checks if Docker Machine is installed by running docker-machine and inspect the result.
*
* @return true if it is installed, false otherwise.
*/
public boolean isDockerMachineInstalled() {
return isDockerMachineInstalled(null);
}
/**
* Executes docker-machine ls command
*
* @param cliPathExec
* location of docker-machine or null if it is on PATH.
*
* @return set of machines
*/
public Set<Machine> list(String cliPathExec) {
Set<Machine> machines = new HashSet<>();
List<String> output = commandLineExecutor.execCommandAsArray(createDockerMachineCommand(cliPathExec), "ls");
Map<String, Index> headerIndex = calculateStartingFieldsIndex(output.get(0));
for (String fields : output.subList(1, output.size())) {
machines.add(parse(headerIndex, fields));
}
return machines;
}
/**
* Executes docker-machine ls --filter field=value command
*
* @param cliPathExec
* location of docker-machine or null if it is on PATH.
* @param field
* to use in condition
* @param value
* value that the field shoudl have
*
* @return set of machines
*/
public Set<Machine> list(String cliPathExec, String field, String value) {
final Set<Machine> machines = new HashSet<>();
List<String> output =
commandLineExecutor.execCommandAsArray(createDockerMachineCommand(cliPathExec), "ls", "--filter",
field + "=" + value);
output = findHeader(output);
if (!output.isEmpty()) {
final Map<String, Index> headerIndex = calculateStartingFieldsIndex(output.get(0));
for (String fields : output.subList(1, output.size())) {
machines.add(parse(headerIndex, fields));
}
}
return machines;
}
private List<String> findHeader(List<String> output) {
for (int i = 0; i < output.size(); i++) {
if (output.get(i).startsWith("NAME")) {
return output.subList(i, output.size());
}
}
return output;
}
private Map<String, Index> calculateStartingFieldsIndex(String header) {
Map<String, Index> headersIndex = new HashMap<>();
String[] headers = header.split("\\s+");
for (int i = 0; i < headers.length; i++) {
String currentHeader = headers[i];
int firstIndex = header.indexOf(currentHeader);
int lastIndex = (i + 1 < headers.length) ? header.indexOf(headers[i + 1]) - 1 : -1;
headersIndex.put(currentHeader, new Index(firstIndex, lastIndex));
}
return headersIndex;
}
/**
* Executes docker-machine ls command
*
* @return set of machines
*/
public Set<Machine> list() {
return this.list(null);
}
/**
* Executes docker-machine ls --filter field=value command
*
* @param field
* to use in condition
* @param value
* value that the field shoudl have
*
* @return set of machines
*/
public Set<Machine> list(String field, String value) {
return this.list(null, field, value);
}
public void grantPermissionToDockerMachine(String machinePath) {
List<String> chmod = commandLineExecutor.execCommandAsArray("chmod", "+x", machinePath);
printOutput(chmod);
}
public void createMachine(String machinePath, String machineDriver, String machineName) {
List<String> create =
commandLineExecutor.execCommandAsArray(machinePath, "create", "--driver", machineDriver, machineName);
printOutput(create);
}
private void printOutput(List<String> lines) {
StringBuilder output = new StringBuilder();
for (String line : lines) {
output.append(line);
output.append(System.lineSeparator());
}
log.info(output.toString());
}
private Machine parse(Map<String, Index> headersIndex, String output) {
String name = resolveField(headersIndex.get("NAME"), output);
String active = resolveField(headersIndex.get("ACTIVE"), output);
String driver = resolveField(headersIndex.get("DRIVER"), output);
String state = resolveField(headersIndex.get("STATE"), output);
String url = resolveField(headersIndex.get("URL"), output);
String swarm = resolveField(headersIndex.get("SWARM"), output);
return new Machine(name, active, driver, state, url, swarm);
}
private String resolveField(Index index, String output) {
if (index.getEndIndex() < 0) {
if (index.getStartIndex() < 0) {
return "";
}
return output.substring(index.getStartIndex(), output.length()).trim();
} else {
return output.substring(index.getStartIndex(), index.getEndIndex() + 1).trim();
}
}
private String createDockerMachineCommand(String dockerMachinePath) {
return dockerMachinePath == null ? DOCKER_MACHINE_EXEC : dockerMachinePath;
}
private class Index {
private int startIndex = -1;
private int endIndex = -1;
public Index(int startIndex, int endIndex) {
this.startIndex = startIndex;
this.endIndex = endIndex;
}
public int getStartIndex() {
return startIndex;
}
public int getEndIndex() {
return endIndex;
}
}
}