package org.arquillian.cube.docker.impl.docker.compose;
import static org.arquillian.cube.docker.impl.util.YamlUtil.asListOfString;
import static org.arquillian.cube.docker.impl.util.YamlUtil.asMap;
import static org.arquillian.cube.docker.impl.util.YamlUtil.asString;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.LinkedHashMap;
import java.util.ArrayList;
import org.arquillian.cube.docker.impl.client.config.CubeContainer;
import org.arquillian.cube.docker.impl.client.config.DockerCompositions;
import org.arquillian.cube.docker.impl.client.config.Network;
public class ComposeBuilder {
private DockerCompositions configuration;
private static final String SERVICES = "services";
private static final String NETWORKS = "networks";
private static final String IP_V4_Address = "ipv4_address";
private static final String IP_V6_Address = "ipv6_address";
private static final String NETWORK_NAME_SUFFIX = "_default";
private Path dockerComposeRootLocation;
ComposeBuilder(Path dockerComposeRootLocation) {
this(dockerComposeRootLocation, new DockerCompositions());
}
private ComposeBuilder(Path dockerComposeRootLocation,
DockerCompositions configuration) {
this.dockerComposeRootLocation = dockerComposeRootLocation;
this.configuration = configuration;
}
@SuppressWarnings("unchecked")
public DockerCompositions build(Map<String, Object> dockerComposeContainerDefinition) {
if (dockerComposeContainerDefinition.containsKey(SERVICES)) {
Map<String, Object> servicesDefinition = asMap(
dockerComposeContainerDefinition, SERVICES);
Set<String> keys = servicesDefinition.keySet();
for (String key : keys) {
ContainerBuilder services = new ContainerBuilder(this.dockerComposeRootLocation);
CubeContainer cubeContainer = services.build(asMap(servicesDefinition, key), DockerComposeConverter.DOCKER_COMPOSE_VERSION_2_VALUE);
if (!dockerComposeContainerDefinition.containsKey(NETWORKS)) {
String networkName = getDefaultNetworkName();
cubeContainer.setNetworks(Arrays.asList(networkName));
cubeContainer.setNetworkMode(networkName);
} else {
final Map<String, Object> serviceDefinition = asMap(servicesDefinition, key);
if (serviceDefinition.containsKey(NETWORKS)) {
Collection<String> serviceNetworks;
Map<String, Object> serviceNetworksConfig = null;
if (serviceDefinition.get(NETWORKS) instanceof ArrayList) {
serviceNetworks = asListOfString(serviceDefinition, NETWORKS);
} else {
serviceNetworksConfig = asMap(serviceDefinition, NETWORKS);
serviceNetworks = serviceNetworksConfig.keySet();
}
if (!serviceNetworks.isEmpty()) {
cubeContainer.setNetworks(new HashSet<>(serviceNetworks));
String networkName = serviceNetworks.iterator().next();
cubeContainer.setNetworkMode(networkName);
if (serviceNetworksConfig != null) {
Map<String, Object> configOption = (LinkedHashMap) serviceNetworksConfig.get(networkName);
setNetworkOptions(configOption, cubeContainer);
}
} else {
throw new IllegalArgumentException("Networks not mentioned under services networks section.");
}
} else {
String networkName = getDefaultNetworkName();
if (!this.configuration.getNetworks().containsKey(networkName)) {
NetworkBuilder networkBuilder = new NetworkBuilder();
Network network = networkBuilder.withDefaultDriver().build();
this.configuration.add(networkName, network);
}
cubeContainer.setNetworks(Arrays.asList(networkName));
cubeContainer.setNetworkMode(networkName);
}
}
this.configuration.add(key, cubeContainer);
}
}
if (dockerComposeContainerDefinition.containsKey(NETWORKS)) {
Map<String, Object> networksDefinition = asMap(
dockerComposeContainerDefinition, NETWORKS);
Set<String> keys = networksDefinition.keySet();
for (String key : keys) {
NetworkBuilder networks = new NetworkBuilder();
Network network = networks.build(asMap(networksDefinition, key));
this.configuration.add(key, network);
}
} else {
String networkName = getDefaultNetworkName();
NetworkBuilder networkBuilder = new NetworkBuilder();
Network network = networkBuilder.withDefaultDriver().build();
this.configuration.add(networkName, network);
}
return this.configuration;
}
private String getDefaultNetworkName() {
return this.dockerComposeRootLocation.toFile()
.getAbsoluteFile()
.getParentFile()
.getName() + NETWORK_NAME_SUFFIX;
}
private void setNetworkOptions(Map<String, Object> networkOption, CubeContainer cubeContainer){
if (networkOption != null) {
if (networkOption.containsKey(IP_V4_Address)) {
cubeContainer.setIpv4Address(asString(networkOption, IP_V4_Address));
}
if (networkOption.containsKey(IP_V6_Address)) {
cubeContainer.setIpv6Address(asString(networkOption, IP_V6_Address));
}
}
}
}