blob: a7c68d1d958b42658f9cb4c8d2c89481e64f37dc [file] [log] [blame]
/*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIESOR 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.aries.containers.docker.local.impl;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.apache.aries.containers.ContainerFactory;
import org.apache.aries.containers.Service;
import org.apache.aries.containers.ServiceConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LocalDockerContainerFactory implements ContainerFactory {
static final Logger LOG = LoggerFactory.getLogger(LocalDockerContainerFactory.class);
private static final String SERVICE_NAME = "service.name";
private static final String DOCKER_MACHINE_VM_NAME = System.getenv("DOCKER_MACHINE_NAME");
private static final boolean CHECK_DOCKER_MACHINE = Stream
.of(System.getenv("PATH").split(Pattern.quote(File.pathSeparator)))
.map(Paths::get)
.anyMatch(path -> Files.exists(path.resolve("docker-machine")));
private static final boolean USE_DOCKER_MACHINE = (DOCKER_MACHINE_VM_NAME != null) && CHECK_DOCKER_MACHINE;
private static final String CONTAINER_HOST = USE_DOCKER_MACHINE
? ProcessRunner.waitFor(ProcessRunner.run("docker-machine", "ip", DOCKER_MACHINE_VM_NAME))
: "localhost";
private volatile LocalDockerController docker;
private final AtomicBoolean initialized = new AtomicBoolean(false);
private final ConcurrentMap<String, Service> services =
new ConcurrentHashMap<>();
private void init() {
if (!initialized.compareAndSet(false, true))
return;
if (docker == null)
docker = new LocalDockerController();
// TODO discover any running docker containers.
}
@Override
public Service getService(ServiceConfig config) throws Exception {
init();
Service existingService = services.get(config.getServiceName());
if (existingService != null)
return existingService;
// TODO return discovered containers if it contains the requested one.
List<ContainerImpl> containers = createContainers(config);
ServiceImpl svc = new ServiceImpl(config, this, containers);
for (ContainerImpl c : containers) {
c.setService(svc);
}
services.put(config.getServiceName(), svc);
return svc;
}
private List<ContainerImpl> createContainers(ServiceConfig config) throws Exception {
List<ContainerImpl> containers = new ArrayList<>();
for (int i=0; i<config.getRequestedInstances(); i++) {
containers.add(createDockerContainer(config));
}
return containers;
}
private ContainerImpl createDockerContainer(ServiceConfig config) throws Exception {
List<String> command = new ArrayList<>();
command.add("-d");
command.add("-l");
command.add(SERVICE_NAME + "=" + config.getServiceName());
String ep = config.getEntryPoint();
if (ep != null) {
command.add("--entrypoint");
command.add(ep);
}
Map<Integer, Integer> ports = new HashMap<>();
for (Integer p : config.getContainerPorts()) {
command.add("-p");
int freePort = getFreePort();
command.add(freePort + ":" + p);
ports.put(p, freePort);
}
for(Map.Entry<String, String> entry : config.getEnvVars().entrySet()) {
command.add("-e");
command.add(entry.getKey() + '=' + entry.getValue());
}
command.add("--cpus");
command.add("" + config.getRequestedCpuUnits() + "");
command.add("-m");
command.add("" + ((int) config.getRequestedMemory()) + "m");
command.add(config.getContainerImage());
command.addAll(Arrays.asList(config.getCommandLine()));
DockerContainerInfo info = docker.run(command);
return new ContainerImpl(info.getID(), info.getIP(), ports);
}
public void destroyDockerContainer(String id, boolean remove) throws Exception {
if (remove) {
docker.remove(id);
} else {
docker.kill(id);
}
}
private int getFreePort() throws IOException {
try (ServerSocket ss = new ServerSocket(0)) {
return ss.getLocalPort();
}
}
public static String getContainerHost() {
return CONTAINER_HOST;
}
}