Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id D71D9200C80 for ; Thu, 25 May 2017 16:34:19 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id D5971160BCA; Thu, 25 May 2017 14:34:19 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 5608C160BC7 for ; Thu, 25 May 2017 16:34:18 +0200 (CEST) Received: (qmail 52725 invoked by uid 500); 25 May 2017 14:34:17 -0000 Mailing-List: contact commits-help@aries.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@aries.apache.org Delivered-To: mailing list commits@aries.apache.org Received: (qmail 52714 invoked by uid 99); 25 May 2017 14:34:17 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 25 May 2017 14:34:17 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 579C3E0016; Thu, 25 May 2017 14:34:17 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: davidb@apache.org To: commits@aries.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: aries-containers git commit: Add very basic initial implementation for local docker usage. Date: Thu, 25 May 2017 14:34:17 +0000 (UTC) archived-at: Thu, 25 May 2017 14:34:20 -0000 Repository: aries-containers Updated Branches: refs/heads/master e09673844 -> 29e1fae95 Add very basic initial implementation for local docker usage. Should work on Linux and on systems with docker-machine Project: http://git-wip-us.apache.org/repos/asf/aries-containers/repo Commit: http://git-wip-us.apache.org/repos/asf/aries-containers/commit/29e1fae9 Tree: http://git-wip-us.apache.org/repos/asf/aries-containers/tree/29e1fae9 Diff: http://git-wip-us.apache.org/repos/asf/aries-containers/diff/29e1fae9 Branch: refs/heads/master Commit: 29e1fae95f4e9cb53a12c7e1df6b3259d9b51f24 Parents: e096738 Author: David Bosschaert Authored: Thu May 25 15:33:16 2017 +0100 Committer: David Bosschaert Committed: Thu May 25 15:33:16 2017 +0100 ---------------------------------------------------------------------- .../org/apache/aries/containers/Container.java | 40 +++++ .../aries/containers/ContainerFactory.java | 2 +- .../org/apache/aries/containers/Service.java | 2 + .../apache/aries/containers/ServiceConfig.java | 25 +-- .../aries/containers/api/ServiceConfigTest.java | 3 +- containers-docker-local/pom.xml | 44 +++++ .../docker/local/impl/ContainerImpl.java | 68 ++++++++ .../docker/local/impl/DockerContainerInfo.java | 37 +++++ .../local/impl/LocalDockerContainerFactory.java | 162 +++++++++++++++++++ .../local/impl/LocalDockerController.java | 70 ++++++++ .../docker/local/impl/ProcessRunner.java | 88 ++++++++++ .../docker/local/impl/ServiceImpl.java | 74 +++++++++ .../containers/docker/local/impl/Streams.java | 59 +++++++ pom.xml | 1 + 14 files changed, 653 insertions(+), 22 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-api/src/main/java/org/apache/aries/containers/Container.java ---------------------------------------------------------------------- diff --git a/containers-api/src/main/java/org/apache/aries/containers/Container.java b/containers-api/src/main/java/org/apache/aries/containers/Container.java new file mode 100644 index 0000000..9c4d569 --- /dev/null +++ b/containers-api/src/main/java/org/apache/aries/containers/Container.java @@ -0,0 +1,40 @@ +/* + * 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; + +import java.util.Map; + +public interface Container extends Comparable { + @Override + default int compareTo(Container other) { + return getID().compareTo(other.getID()); + } + + void destroy(); + String getID(); + String getIPAddress(); + + /* The maps of ports exposed to the outside by the container. + * It maps an internal port to an outside port. + * @return a map of exposed ports. + */ + Map getExposedPorts(); + + Service getService(); +} http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-api/src/main/java/org/apache/aries/containers/ContainerFactory.java ---------------------------------------------------------------------- diff --git a/containers-api/src/main/java/org/apache/aries/containers/ContainerFactory.java b/containers-api/src/main/java/org/apache/aries/containers/ContainerFactory.java index 3bdaf8d..ec69264 100644 --- a/containers-api/src/main/java/org/apache/aries/containers/ContainerFactory.java +++ b/containers-api/src/main/java/org/apache/aries/containers/ContainerFactory.java @@ -4,5 +4,5 @@ import org.osgi.annotation.versioning.ProviderType; @ProviderType public interface ContainerFactory { - Service getService(ServiceConfig config); + Service getService(ServiceConfig config) throws Exception; } http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-api/src/main/java/org/apache/aries/containers/Service.java ---------------------------------------------------------------------- diff --git a/containers-api/src/main/java/org/apache/aries/containers/Service.java b/containers-api/src/main/java/org/apache/aries/containers/Service.java index 0132ac4..6b334d0 100644 --- a/containers-api/src/main/java/org/apache/aries/containers/Service.java +++ b/containers-api/src/main/java/org/apache/aries/containers/Service.java @@ -32,4 +32,6 @@ public interface Service { * @return The instance count. */ int getActualInstanceCount(); + + void setInstanceCount(int count); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-api/src/main/java/org/apache/aries/containers/ServiceConfig.java ---------------------------------------------------------------------- diff --git a/containers-api/src/main/java/org/apache/aries/containers/ServiceConfig.java b/containers-api/src/main/java/org/apache/aries/containers/ServiceConfig.java index 85c28b2..8523fca 100644 --- a/containers-api/src/main/java/org/apache/aries/containers/ServiceConfig.java +++ b/containers-api/src/main/java/org/apache/aries/containers/ServiceConfig.java @@ -33,7 +33,6 @@ public class ServiceConfig { private final String entryPoint; private final Map envVars; // private final List healthChecks; - private final int mainPort; private final double requestedCPUunits; private final int requestedInstances; private final double requestedMemory; // in MiB @@ -41,14 +40,13 @@ public class ServiceConfig { private ServiceConfig(String[] commandLine, String containerImage, List containerPorts, String entryPoint, - Map envVars, int mainPort, double requestedCPUunits, int requestedInstances, double requestedMemory, + Map envVars, double requestedCPUunits, int requestedInstances, double requestedMemory, String serviceName) { this.commandLine = commandLine; this.containerImage = containerImage; this.containerPorts = containerPorts; this.entryPoint = entryPoint; this.envVars = envVars; - this.mainPort = mainPort; this.requestedCPUunits = requestedCPUunits; this.requestedInstances = requestedInstances; this.requestedMemory = requestedMemory; @@ -75,10 +73,6 @@ public class ServiceConfig { return envVars; } - public int getMainPort() { - return mainPort; - } - public double getRequestedCpuUnits() { return requestedCPUunits; } @@ -91,6 +85,10 @@ public class ServiceConfig { return requestedMemory; } + /** + * The name of the service deployment. This has to be unique in the system. + * @return The name of the service. + */ public String getServiceName() { return serviceName; } @@ -108,7 +106,6 @@ public class ServiceConfig { private double requestedCpuUnits = 0.5; private int requestedInstances = 1; private double requestedMemory = 64; - private int mainPort = -1; private List ports = new ArrayList<>(); private String serviceName; @@ -154,23 +151,13 @@ public class ServiceConfig { } public Builder port(int port) { - return port(port, false); - } - - public Builder port(int port, boolean main) { this.ports.add(port); - if (main) { - if (this.mainPort != -1) - throw new IllegalStateException("A main port has already been set: " + mainPort); - - this.mainPort = port; - } return this; } public ServiceConfig build() { return new ServiceConfig(commandLine, containerImage, ports, entryPoint, - envMap, mainPort, requestedCpuUnits, requestedInstances, requestedMemory, + envMap, requestedCpuUnits, requestedInstances, requestedMemory, serviceName); } } http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-api/src/test/java/org/apache/aries/containers/api/ServiceConfigTest.java ---------------------------------------------------------------------- diff --git a/containers-api/src/test/java/org/apache/aries/containers/api/ServiceConfigTest.java b/containers-api/src/test/java/org/apache/aries/containers/api/ServiceConfigTest.java index d8b7ef2..752872d 100644 --- a/containers-api/src/test/java/org/apache/aries/containers/api/ServiceConfigTest.java +++ b/containers-api/src/test/java/org/apache/aries/containers/api/ServiceConfigTest.java @@ -28,7 +28,7 @@ public class ServiceConfigTest { env("a", "b c d"). instances(17). memory(5.5). - port(8080, true). + port(8080). port(9090). build(); @@ -42,7 +42,6 @@ public class ServiceConfigTest { assertEquals(expectedEnv, sc.getEnvVars()); assertEquals(17, sc.getRequestedInstances()); assertEquals(5.5, sc.getRequestedMemory(), 0.01); - assertEquals(8080, sc.getMainPort()); assertEquals(Arrays.asList(8080, 9090), sc.getContainerPorts()); } http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-docker-local/pom.xml ---------------------------------------------------------------------- diff --git a/containers-docker-local/pom.xml b/containers-docker-local/pom.xml new file mode 100644 index 0000000..ae7cada --- /dev/null +++ b/containers-docker-local/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.apache.aries.containers + org.apache.aries.containers.parent + 0.0.1-SNAPSHOT + ../containers-parent + + + org.apache.aries.containers.docker.local + jar + Apache Aries Containers impl for local Docker use + + + + ${project.groupId} + org.apache.aries.containers.api + ${project.version} + provided + + + + http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ContainerImpl.java ---------------------------------------------------------------------- diff --git a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ContainerImpl.java b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ContainerImpl.java new file mode 100644 index 0000000..66f3f83 --- /dev/null +++ b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ContainerImpl.java @@ -0,0 +1,68 @@ +/* + * 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.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.aries.containers.Container; +import org.apache.aries.containers.Service; + +public class ContainerImpl implements Container { + private final String id; + private final String ip; + private final Map ports; + private ServiceImpl service; + + ContainerImpl(String id, String ip, Map ports) { + this.id = id; + this.ip = ip; + this.ports = Collections.unmodifiableMap(new HashMap<>(ports)); + } + + @Override + public void destroy() { + service.killAndReplaceContainer(this); + } + + @Override + public Map getExposedPorts() { + return ports; + } + + @Override + public String getID() { + return id; + } + + @Override + public String getIPAddress() { + return ip; + } + + @Override + public Service getService() { + return service; + } + + void setService(ServiceImpl svc) { + service = svc; + } +} http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/DockerContainerInfo.java ---------------------------------------------------------------------- diff --git a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/DockerContainerInfo.java b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/DockerContainerInfo.java new file mode 100644 index 0000000..8caa6af --- /dev/null +++ b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/DockerContainerInfo.java @@ -0,0 +1,37 @@ +/* + * 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; + +class DockerContainerInfo { + private final String id; + private final String ip; + + public DockerContainerInfo(String id, String ipAddress) { + this.id = id; + this.ip = ipAddress; + } + + public String getID() { + return id; + } + + public String getIP() { + return ip; + } +} http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerContainerFactory.java ---------------------------------------------------------------------- diff --git a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerContainerFactory.java b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerContainerFactory.java new file mode 100644 index 0000000..a7c68d1 --- /dev/null +++ b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerContainerFactory.java @@ -0,0 +1,162 @@ +/* + * 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 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 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 createContainers(ServiceConfig config) throws Exception { + List containers = new ArrayList<>(); + + for (int i=0; i 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 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 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; + } +} http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerController.java ---------------------------------------------------------------------- diff --git a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerController.java b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerController.java new file mode 100644 index 0000000..2fecfa7 --- /dev/null +++ b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerController.java @@ -0,0 +1,70 @@ +/* + * 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.LineNumberReader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; + +public class LocalDockerController { + + public String kill(String id) throws Exception { + return kill(id, "KILL"); + } + + private String kill(String id, String signal) throws Exception { + return runCommandExpectSingleID("docker", "kill", "-s", signal, id); + } + + public String remove(String id) throws Exception { + // Kill the docker container if its still running + return runCommandExpectSingleID("docker", "rm", "-f", id); + } + + public DockerContainerInfo run(List command) throws Exception { + List execCmd = new ArrayList<>(); + execCmd.add("docker"); + execCmd.add("run"); + execCmd.addAll(command); + + String id = runCommandExpectSingleID(execCmd.toArray(new String [] {})); + return new DockerContainerInfo(id, LocalDockerContainerFactory.getContainerHost()); + } + + String runCommandExpectSingleID(String ... command) throws Exception { + String res = ProcessRunner.waitFor(ProcessRunner.run(command)); + if (res != null) { + res = res.trim(); + String lastLine = res; + try ( final LineNumberReader lnr = new LineNumberReader(new StringReader(res)) ) { + String line; + while ( ( line = lnr.readLine()) != null ) { + lastLine = line; + } + } + if ( lastLine.indexOf(' ') != -1 ) { + throw new Exception("Unable to execute docker command: " + res); + } + res = lastLine; + } + + return res; + } +} http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ProcessRunner.java ---------------------------------------------------------------------- diff --git a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ProcessRunner.java b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ProcessRunner.java new file mode 100644 index 0000000..b145026 --- /dev/null +++ b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ProcessRunner.java @@ -0,0 +1,88 @@ +/* + * 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.util.Arrays; +import java.util.Collections; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProcessRunner { + // For testing purposes + public static final String SKIP_RUN = ProcessRunner.class.getName() + ".skiprun"; + + private static final Logger LOG = LoggerFactory.getLogger(ProcessRunner.class); + + private ProcessRunner() { + // Util class do not instantiate + } + + public static Process run(String ... args) { + try { + return run(Collections.emptyMap(), args); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } + + public static Process run(Map envVars, String ... args) throws IOException, InterruptedException { + return run(envVars, null, args); + } + + public static Process run(Map envVars, final File dir, String ... args) throws IOException { + if ("true".equals(System.getProperty(SKIP_RUN))) { + LOG.debug("Skipping the external command run as configured."); + return null; + } + + LOG.info("Executing shell command: {} with environment {}", args, envVars); + + try { + ProcessBuilder builder = new ProcessBuilder(args); + if ( dir != null ) { + builder.directory(dir); + } + builder.redirectErrorStream(true); + Map environ = builder.environment(); + environ.putAll(envVars); + + Process process = builder.start(); + + return process; + } catch (IOException e) { + LOG.error("Problem executing command: " + Arrays.toString(args), e); + throw e; + } + } + + public static String waitFor(final Process process) { + try { + process.waitFor(); + String res = new String(Streams.suck(process.getInputStream())).trim(); + LOG.debug("Result: {}", res); + return res; + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ServiceImpl.java ---------------------------------------------------------------------- diff --git a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ServiceImpl.java b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ServiceImpl.java new file mode 100644 index 0000000..4577f70 --- /dev/null +++ b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ServiceImpl.java @@ -0,0 +1,74 @@ +/* + * 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.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.aries.containers.Service; +import org.apache.aries.containers.ServiceConfig; + +public class ServiceImpl implements Service { + private final ServiceConfig config; + private final List containers; + private final LocalDockerContainerFactory factory; + + public ServiceImpl(ServiceConfig config, + LocalDockerContainerFactory factory, + List containers) { + this.config = config; + this.factory = factory; + this.containers = new CopyOnWriteArrayList<>(containers); + } + + @Override + public void destroy() { + setInstanceCount(0); + } + + @Override + public int getActualInstanceCount() { + return containers.size(); // TODO obtain live + } + + @Override + public void setInstanceCount(int count) { + try { + int curSize = containers.size(); + if (count < curSize) { + for (int i=0 ; i < curSize - count; i++) { + killContainer(containers.remove(0)); + } + } else { + // TODO implement scaling up + } + } catch (Exception e) { + LocalDockerContainerFactory.LOG.error("Problem changing instance count of service {} to {}", + config.getServiceName(), count, e); + } + } + + private void killContainer(ContainerImpl container) throws Exception { + factory.destroyDockerContainer(container.getID(), true); + } + + public void killAndReplaceContainer(ContainerImpl containerImpl) { + // TODO implement + } +} http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/Streams.java ---------------------------------------------------------------------- diff --git a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/Streams.java b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/Streams.java new file mode 100644 index 0000000..37a4860 --- /dev/null +++ b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/Streams.java @@ -0,0 +1,59 @@ +/* + * 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.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public final class Streams { + private Streams() { + // Util class do not instantiate + } + + public static void pump(InputStream is, OutputStream os) throws IOException { + byte[] bytes = new byte[16384]; + + int length = 0; + int offset = 0; + + while ((length = is.read(bytes, offset, bytes.length - offset)) != -1) { + offset += length; + + if (offset == bytes.length) { + os.write(bytes, 0, bytes.length); + offset = 0; + } + } + if (offset != 0) { + os.write(bytes, 0, offset); + } + } + + public static byte [] suck(InputStream is) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + pump(is, baos); + return baos.toByteArray(); + } finally { + is.close(); + } + } +} http://git-wip-us.apache.org/repos/asf/aries-containers/blob/29e1fae9/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 752b467..881f9c4 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,7 @@ containers-parent containers-api + containers-docker-local