diff --git a/api/Dockerfile b/api/Dockerfile new file mode 100644 index 00000000..1ac12efb --- /dev/null +++ b/api/Dockerfile @@ -0,0 +1,6 @@ +FROM containersol/alpine3.3-java8-jre:v1 +MAINTAINER Container Solutions BV + +ADD minimesos-api.jar /usr/local/share/minimesos/minimesos-api.jar + +ENTRYPOINT java -Dminimesos.dir=/tmp/.minimesos -jar /usr/local/share/minimesos/minimesos-api.jar diff --git a/api/build.gradle b/api/build.gradle new file mode 100644 index 00000000..f1fa1032 --- /dev/null +++ b/api/build.gradle @@ -0,0 +1,127 @@ +import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage +import com.bmuschko.gradle.docker.tasks.image.DockerPushImage +import com.bmuschko.gradle.docker.tasks.image.DockerTagImage + +apply plugin: 'java' +apply plugin: 'application' +apply plugin: 'com.bmuschko.docker-remote-api' + +repositories { + mavenLocal() + mavenCentral() + maven { + url "https://jitpack.io" + } +} + +group = "com.containersol.minimesos" + +dependencies { + compile 'com.beust:jcommander:1.48' + compile 'org.slf4j:slf4j-api:1.7.12' + compile 'com.sparkjava:spark-core:2.5' + compile 'com.google.code.gson:gson:2.3.1' + + compile project(':minimesos') + + testCompile 'junit:junit:4.11' + testCompile "org.mockito:mockito-core:1.+" + // using guru.nidi as maintenanance of the original project is dropped https://github.com/clarkware/jdepend/pull/9 + testCompile "guru.nidi:jdepend:2.9.5" +} + +mainClassName = "com.containersol.minimesos.api.Main" + +ext { + imageName = imagePrefix + '/minimesos-api' +} + +test { + testLogging { + showStandardStreams = true + } +} + +task executableJar(type: Jar) { + baseName = "minimesos-api" + from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } + with jar + manifest { + attributes( + 'Main-Class': mainClassName, + 'Implementation-Version': project.version + ) + } + exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA' +} + +artifacts { + archives executableJar +} + +task copyFilesForDocker(type: Copy) { + dependsOn 'executableJar' + from "build/libs/minimesos-api-${project.version}.jar" + into 'build/docker' + rename { String fileName -> + fileName.replace("-${project.version}", "") + } +} + +task copyDockerfile(type: Copy) { + dependsOn 'copyFilesForDocker' + from "Dockerfile" + into 'build/docker' +} + +afterEvaluate { project -> + if (new File(project.projectDir, 'Dockerfile').exists()) { + if (!project.hasProperty('imageName')) { + throw new GradleException('Root directory of ' + project.name + + ' contains Dockerfile, but it does not define project.ext.imageName value') + } + docker.url = 'unix:///var/run/docker.sock' + if (!System.properties['os.name'].equals('Mac OS X')) { + docker.certPath = null + } + if (System.env.DOCKER_HOST) { + docker.url = "$System.env.DOCKER_HOST".replace("tcp", "https") + if (System.env.DOCKER_CERT_PATH) { + docker.certPath = new File(System.env.DOCKER_CERT_PATH) + } + } + task buildDockerImage(type: DockerBuildImage, dependsOn: [copyDockerfile], description: 'build Docker image') { + inputDir = new File("${buildDir}/docker") + tag = project.imageName + } + project.build.dependsOn buildDockerImage + ['snapshot', 'version'].each { aTag -> + String uppercasedName = aTag.capitalize() + task "tagDockerImageWith$uppercasedName"(type: DockerTagImage, description: 'tag Docker image') { + imageId = project.imageName + tag = ('version'.equals(aTag)) ? project.version : aTag + repository = project.imageName + force = true + } + task "publishDockerImageWith$uppercasedName"(type: DockerPushImage, dependsOn: ["tagDockerImageWith$uppercasedName"], + description: 'publish Docker image') { + imageName = project.imageName + tag = ('version'.equals(aTag)) ? project.version : aTag + doFirst { + ['dockerHubUsername', 'dockerHubPassword', 'dockerHubEmail'].each { + assert project.hasProperty(it): 'Undefined "' + it + '" property' + } + docker { + registryCredentials { + username = project.property('dockerHubUsername') + password = project.property('dockerHubPassword') + email = project.property('dockerHubEmail') + } + } + } + } + } + } +} + +assemble.dependsOn executableJar diff --git a/api/src/main/java/com/containersol/minimesos/api/ApiServer.java b/api/src/main/java/com/containersol/minimesos/api/ApiServer.java new file mode 100644 index 00000000..eb8e9026 --- /dev/null +++ b/api/src/main/java/com/containersol/minimesos/api/ApiServer.java @@ -0,0 +1,67 @@ +package com.containersol.minimesos.api; + +import com.containersol.minimesos.cluster.ClusterRepository; +import com.containersol.minimesos.cluster.MesosCluster; +import com.containersol.minimesos.config.ClusterConfig; +import com.containersol.minimesos.config.ConfigParser; +import com.containersol.minimesos.mesos.MesosClusterContainersFactory; +import spark.Spark; + +import java.net.UnknownHostException; + +/** + * minimesos API server + */ +public class ApiServer { + + public static final int PORT = 8080; + + private ClusterRepository repository; + + private final MesosClusterContainersFactory factory; + + private MesosCluster mesosCluster; + + public ApiServer() { + repository = new ClusterRepository(); + factory = new MesosClusterContainersFactory(); + } + + public static void main(String[] args) throws UnknownHostException { + ApiServer apiServer = new ApiServer(); + apiServer.start(); + } + + public void start() { + Spark.port(PORT); + + Spark.post("/start", "text/plain", (request, response) -> { + if (mesosCluster != null) { + return new ClusterStartedResponse(mesosCluster.getClusterId()); + } else { + ClusterConfig clusterConfig = new ConfigParser().parse(request.body()); + mesosCluster = factory.createMesosCluster(clusterConfig); + mesosCluster.start(); + return new ClusterStartedResponse(mesosCluster.getClusterId()); + } + }, JsonUtils.json()); + + Spark.get("/info", (req, res) -> "No cluster is running"); + + Spark.exception(Exception.class, (exception, request, response) -> { + exception.printStackTrace(); + }); + } + + public void stop() { + if (mesosCluster != null) { + mesosCluster.destroy(factory); + } + + Spark.stop(); + } + + public String getServiceUrl() { + return "http://localhost:" + PORT; + } +} diff --git a/api/src/main/java/com/containersol/minimesos/api/ClusterStartedResponse.java b/api/src/main/java/com/containersol/minimesos/api/ClusterStartedResponse.java new file mode 100644 index 00000000..e0bbef1a --- /dev/null +++ b/api/src/main/java/com/containersol/minimesos/api/ClusterStartedResponse.java @@ -0,0 +1,10 @@ +package com.containersol.minimesos.api; + +public class ClusterStartedResponse { + + private String clusterId; + + public ClusterStartedResponse(String clusterId) { + this.clusterId = clusterId; + } +} diff --git a/api/src/main/java/com/containersol/minimesos/api/JsonUtils.java b/api/src/main/java/com/containersol/minimesos/api/JsonUtils.java new file mode 100644 index 00000000..fd0264bb --- /dev/null +++ b/api/src/main/java/com/containersol/minimesos/api/JsonUtils.java @@ -0,0 +1,15 @@ +package com.containersol.minimesos.api; + +import com.google.gson.Gson; + +import spark.ResponseTransformer; + +public class JsonUtils { + + public static String toJson(Object object) { + return new Gson().toJson(object); + } + public static ResponseTransformer json() { + return JsonUtils::toJson; + } +} diff --git a/api/src/main/resources/logback.xml b/api/src/main/resources/logback.xml new file mode 100644 index 00000000..39a568c1 --- /dev/null +++ b/api/src/main/resources/logback.xml @@ -0,0 +1,14 @@ + + + + System.out + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + diff --git a/api/src/test/java/com/containersol/minimesos/api/ApiServerTest.java b/api/src/test/java/com/containersol/minimesos/api/ApiServerTest.java new file mode 100644 index 00000000..d396af6f --- /dev/null +++ b/api/src/test/java/com/containersol/minimesos/api/ApiServerTest.java @@ -0,0 +1,62 @@ +package com.containersol.minimesos.api; + +import com.containersol.minimesos.cluster.MesosCluster; +import com.containersol.minimesos.mesos.MesosClusterContainersFactory; +import com.mashape.unirest.http.HttpResponse; +import com.mashape.unirest.http.Unirest; +import com.mashape.unirest.http.exceptions.UnirestException; + +import org.apache.commons.io.IOUtils; +import org.json.JSONObject; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.FileInputStream; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + +public class ApiServerTest { + + private static ApiServer apiServer; + + @BeforeClass + public static void before() { + apiServer = new ApiServer(); + apiServer.start(); + } + + @AfterClass + public static void after() { + apiServer.stop(); + } + + @Test + public void testInfo() throws UnirestException { + HttpResponse response = Unirest.get(apiServer.getServiceUrl() + "/info").asString(); + + assertEquals("No cluster is running", response.getBody()); + } + + @Test + public void testStart() throws UnirestException, IOException { + HttpResponse firstResponse = Unirest.post(apiServer.getServiceUrl() + "/start").body(IOUtils.toByteArray(new FileInputStream("src/test/resources/minimesosFile-apiServer"))).asString(); + + assertEquals(200, firstResponse.getStatus()); + + JSONObject jsonObject = new JSONObject(firstResponse.getBody()); + String clusterId = jsonObject.getString("clusterId"); + + MesosCluster mesosCluster = MesosCluster.loadCluster(clusterId, new MesosClusterContainersFactory()); + assertEquals(1, mesosCluster.getAgents().size()); + + HttpResponse secondResponse = Unirest.post(apiServer.getServiceUrl() + "/start").body(IOUtils.toByteArray(new FileInputStream("src/test/resources/minimesosFile-apiServer"))).asString(); + + assertEquals(200, firstResponse.getStatus()); + assertEquals(200, secondResponse.getStatus()); + + assertEquals(firstResponse.getBody(), secondResponse.getBody()); + } + +} diff --git a/api/src/test/resources/minimesosFile-apiServer b/api/src/test/resources/minimesosFile-apiServer new file mode 100644 index 00000000..e1eed60d --- /dev/null +++ b/api/src/test/resources/minimesosFile-apiServer @@ -0,0 +1,54 @@ +minimesos { + clusterName = "api-server-cluster" + mapPortsToHost = false + loggingLevel = "INFO" + mapAgentSandboxVolume = false + mesosVersion = "0.25" + timeout = 60 + + agent { + imageName = "containersol/mesos-agent" + imageTag = "# derive from mesos version" + loggingLevel = "# INHERIT FROM CLUSTER" + portNumber = 5051 + + resources { + + cpu { + role = "*" + value = 1 + } + + disk { + role = "*" + value = 200 + } + + mem { + role = "*" + value = 256 + } + + ports { + role = "*" + value = "[31000-32000]" + } + } + } + + consul { + imageName = "containersol/consul-server" + imageTag = "0.6" + } + + master { + imageName = "containersol/mesos-master" + imageTag = "# derive from mesos version" + loggingLevel = "# INHERIT FROM CLUSTER" + } + + zookeeper { + imageName = "jplock/zookeeper" + imageTag = "3.4.6" + } +} diff --git a/cli/src/main/java/com/containersol/minimesos/main/ApiContainer.java b/cli/src/main/java/com/containersol/minimesos/main/ApiContainer.java new file mode 100644 index 00000000..bf79e3b5 --- /dev/null +++ b/cli/src/main/java/com/containersol/minimesos/main/ApiContainer.java @@ -0,0 +1,32 @@ +package com.containersol.minimesos.main; + +import com.containersol.minimesos.config.ContainerConfigBlock; +import com.containersol.minimesos.container.AbstractContainer; +import com.containersol.minimesos.docker.DockerClientFactory; +import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.model.ExposedPort; + +import static com.containersol.minimesos.util.EnvironmentBuilder.newEnvironment; +import static java.lang.String.valueOf; + +public class ApiContainer extends AbstractContainer { + + public ApiContainer() { + super(new ContainerConfigBlock("containersol/minimesos-api", "latest")); + } + + @Override protected CreateContainerCmd dockerCommand() { + ExposedPort exposedPort = ExposedPort.tcp(0); + return DockerClientFactory.build().createContainerCmd(getImageName() + ":" + getImageTag()) + .withEnv(newEnvironment() + .withValue("PORT", valueOf(exposedPort.getPort())) + .createEnvironment()) + .withPrivileged(true) + .withName(getName()) + .withExposedPorts(exposedPort); + } + + @Override public String getRole() { + return "api"; + } +} diff --git a/cli/src/main/java/com/containersol/minimesos/main/CommandServe.java b/cli/src/main/java/com/containersol/minimesos/main/CommandServe.java new file mode 100644 index 00000000..83838699 --- /dev/null +++ b/cli/src/main/java/com/containersol/minimesos/main/CommandServe.java @@ -0,0 +1,36 @@ +package com.containersol.minimesos.main; + +import com.beust.jcommander.Parameters; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Initializes a default minimesosFile in the directory where minimesos is run + */ +@Parameters(separators = "=", commandDescription = "Start the API Webservice") +public class CommandServe implements Command { + + private static final Logger LOGGER = LoggerFactory.getLogger(CommandServe.class); + + public static final String CLINAME = "serve"; + + @Override + public boolean validateParameters() { + return true; + } + + @Override + public String getName() { + return CLINAME; + } + + @Override + public void execute() { + + ApiContainer apiContainer = new ApiContainer(); + apiContainer.start(5); + + } + +} diff --git a/cli/src/main/java/com/containersol/minimesos/main/Main.java b/cli/src/main/java/com/containersol/minimesos/main/Main.java index 0dd7f1c5..8b2d9894 100644 --- a/cli/src/main/java/com/containersol/minimesos/main/Main.java +++ b/cli/src/main/java/com/containersol/minimesos/main/Main.java @@ -46,6 +46,7 @@ public class Main { public static void main(String[] args) { Main main = new Main(); main.addCommand(new CommandUp()); + main.addCommand(new CommandServe()); main.addCommand(new CommandDestroy()); main.addCommand(new CommandHelp()); main.addCommand(new CommandInstall()); diff --git a/cli/src/main/resources/logback.xml b/cli/src/main/resources/logback.xml new file mode 100644 index 00000000..aa7d4a71 --- /dev/null +++ b/cli/src/main/resources/logback.xml @@ -0,0 +1,16 @@ + + + + System.out + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}: %msg%n + + + + + + + + + + diff --git a/docs/index.md b/docs/index.md index 200edb3c..93a615e3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,6 +9,7 @@ If you have used Vagrant and Docker before, the set of the commands will be very - Website https://minimesos.org/ - Blog https://minimesos.org/blog - Interactive tutorial https://minimesos.org/try + - API Webservice `` ## System Requirements @@ -288,3 +289,126 @@ export LIBPROCESS_IP=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | ``` This ensures your executor task will be assigned an interface to allow communication within the cluster. + +# minimesos API Webservice + +The minimesos API provides functionality to run and monitor a single Mesos cluster in minimesos. + +## Start minimesos cluster [/start] + +### POST + +Starts the Mesos cluster and returns it's ID. + ++ Request (text/plain) + + ``` + Contents of a minimesosFile + ``` + ++ Response 200 (application/json) + + ```json + { + "cluster_id": "123456", + "endpoints": { + "network-gateway": { + "ip": "172.17.0.1" + }, + "master": { + "ip": "172.10.0.5", + "endpoint": "http://172.17.0.4:5050" + }, + "zookeeper": { + "ip": "172.10.0.7", + "endpoint": "zk://172.17.0.3:2181/mesos" + }, + "marathon": { + "ip": "172.10.0.8", + "endpoint": "http://172.17.0.8:8080" + }, + "api": { + "ip": "172.10.0.10", + "endpoint": "http://172.10.0.10" + } + } + } + ``` + ++ Response 500 (text/plain) + + ``` + Cluster failed to start: + ``` + +## Retrieve cluster info [/info] + +### GET + +Returns all info about the running cluster. + ++ Response 200 (application/json) + + ```json + { + "cluster_id": "123456", + "endpoints": { + "master": "172.10.0.5", + "agent": "172.10.0.6", + "zookeeper": "172.10.0.7", + "marathon": "172.10.0.8", + "api": "172.10.0.1" + } + } + ``` + +## Install Marathon framework [/install] + +Install a Mesos framework using Marathon. The input is expected to be a valid Marathon file. + +### POST + +* Request (application/json) + + ```json + { + "id": "elasticsearch", + "container": { + "docker": { + "image": "mesos/elasticsearch-scheduler:1.0.1", + "network": "BRIDGE" + } + }, + "args": [ + "--zookeeperMesosUrl", "${MINIMESOS_ZOOKEEPER}", + "--useIpAddress", "true", + "--frameworkUseDocker", "false", + "--elasticsearchNodes", "1" + ], + "cpus": 0.2, + "mem": 512.0, + "env": { + "JAVA_OPTS": "-Xms128m -Xmx256m" + }, + "instances": 1 + } + ``` +* Response 200 (text/plain) + + ``` + + ``` +* Response 500 (text/plain) + + ``` + Failed to install framework: + ``` + +## Uninstall Marathon framework [/uninstall/{framework_id}] + +Uninstall a framework using Marathon + ++ Parameters + + framework_id: (string) - The id of the framework that will be uninstalled + +### POST diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f02243ee..b70f4868 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Apr 21 17:15:12 CEST 2016 +#Thu Jun 02 12:03:52 CEST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.12-all.zip diff --git a/minimesos/src/main/java/com/containersol/minimesos/container/AbstractContainer.java b/minimesos/src/main/java/com/containersol/minimesos/container/AbstractContainer.java index f6b65862..7ab9c038 100644 --- a/minimesos/src/main/java/com/containersol/minimesos/container/AbstractContainer.java +++ b/minimesos/src/main/java/com/containersol/minimesos/container/AbstractContainer.java @@ -1,5 +1,11 @@ package com.containersol.minimesos.container; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.SecureRandom; +import java.util.List; +import java.util.concurrent.TimeUnit; + import com.containersol.minimesos.MinimesosException; import com.containersol.minimesos.cluster.ClusterProcess; import com.containersol.minimesos.cluster.MesosCluster; @@ -10,16 +16,11 @@ import com.github.dockerjava.api.model.Container; import com.github.dockerjava.api.model.Image; import com.jayway.awaitility.core.ConditionTimeoutException; + import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.SecureRandom; -import java.util.List; -import java.util.concurrent.TimeUnit; - import static com.jayway.awaitility.Awaitility.await; /** @@ -78,7 +79,7 @@ public String getImageTag() { protected abstract CreateContainerCmd dockerCommand(); /** - * Starts the container and waits until is started + * Starts the container and waits until is started or already exited without error. * * @param timeout in seconds */ @@ -93,19 +94,13 @@ public void start(int timeout) { DockerClientFactory.build().startContainerCmd(containerId).exec(); try { - await().atMost(timeout, TimeUnit.SECONDS).pollDelay(1, TimeUnit.SECONDS).until(() -> { - List containers = DockerClientFactory.build().listContainersCmd().withShowAll(true).exec(); - for (Container container : containers) { - if (container.getId().equals(containerId)) { - return true; - } - } - return false; + Container container = DockerContainersUtil.getContainer(containerId); + return container != null && (container.getStatus().startsWith("Up") || container.getStatus().startsWith("Exited (0)")); }); - } catch (ConditionTimeoutException cte) { - String errorMessage = String.format("Container [%s] did not start within %d seconds.", createCommand.getName(), timeout); + String errorMessage = String.format("Container [%s] did not start within %d seconds. Status is '%s'", createCommand.getName(), timeout, + DockerContainersUtil.getContainer(containerId).getStatus()); LOGGER.error(errorMessage); try { for (String logLine : DockerContainersUtil.getDockerLogs(containerId)) { @@ -151,6 +146,7 @@ public URI getServiceUrl() { /** * Enables derived classes to override + * * @return protocol of the service */ protected String getServiceProtocol() { @@ -159,6 +155,7 @@ protected String getServiceProtocol() { /** * Enables derived classes to override + * * @return port of the service */ protected int getServicePort() { @@ -167,6 +164,7 @@ protected int getServicePort() { /** * Enables derived classes to override + * * @return protocol of the service */ protected String getServicePath() { diff --git a/minimesos/src/main/java/com/containersol/minimesos/docker/DockerContainersUtil.java b/minimesos/src/main/java/com/containersol/minimesos/docker/DockerContainersUtil.java index 852cd4de..00cdbcc5 100644 --- a/minimesos/src/main/java/com/containersol/minimesos/docker/DockerContainersUtil.java +++ b/minimesos/src/main/java/com/containersol/minimesos/docker/DockerContainersUtil.java @@ -1,5 +1,14 @@ package com.containersol.minimesos.docker; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + import com.containersol.minimesos.MinimesosException; import com.github.dockerjava.api.DockerException; import com.github.dockerjava.api.command.InspectContainerResponse; @@ -10,16 +19,6 @@ import com.github.dockerjava.core.command.LogContainerResultCallback; import com.github.dockerjava.core.command.PullImageResultCallback; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - /** * Immutable utility class, which represents set of docker containers with filters and operations on this list */ @@ -246,14 +245,9 @@ public static String getGatewayIpAddress(String containerId) { */ public static Container getContainer(String containerId) { List containers = DockerClientFactory.build().listContainersCmd().withShowAll(true).exec(); - Container container = null; - if (containers != null && !containers.isEmpty()) { - Optional optional = containers.stream().filter(c -> c.getId().equals(containerId)).findFirst(); - if (optional.isPresent()) { - container = optional.get(); - } - } - return container; + if (containers == null) return null; + + return containers.stream().filter(c -> c.getId().equals(containerId)).findFirst().orElse(null); } } diff --git a/minimesos/src/test/java/com/containersol/minimesos/RunTaskTest.java b/minimesos/src/test/java/com/containersol/minimesos/RunTaskTest.java index 98c36dde..a2204d37 100644 --- a/minimesos/src/test/java/com/containersol/minimesos/RunTaskTest.java +++ b/minimesos/src/test/java/com/containersol/minimesos/RunTaskTest.java @@ -11,12 +11,13 @@ import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.model.Frame; import com.github.dockerjava.core.command.LogContainerResultCallback; -import com.jayway.awaitility.Awaitility; import org.junit.ClassRule; import org.junit.Test; import java.util.concurrent.TimeUnit; +import static com.jayway.awaitility.Awaitility.*; + public class RunTaskTest { private static final String TASK_CLUSTER_ROLE = "test"; @@ -63,17 +64,14 @@ protected CreateContainerCmd dockerCommand() { } }; - CLUSTER.addAndStartProcess(mesosAgent); - LogContainerTestCallback cb = new LogContainerTestCallback(); - DockerClientFactory.build().logContainerCmd(mesosAgent.getContainerId()).withStdOut(true).exec(cb); - cb.awaitCompletion(); - - Awaitility.await().atMost(60, TimeUnit.SECONDS).until(() -> { - LogContainerTestCallback cb1 = new LogContainerTestCallback(); - DockerClientFactory.build().logContainerCmd(mesosAgent.getContainerId()).withStdOut(true).exec(cb1); - cb1.awaitCompletion(); - String log = cb1.toString(); - return log.contains("Received status update TASK_FINISHED for task test-cmd"); + mesosAgent.start(10); + + await().timeout(60, TimeUnit.SECONDS).until(() -> { + LogContainerTestCallback cb = new LogContainerTestCallback(); + DockerClientFactory.build().logContainerCmd(mesosAgent.getContainerId()).withStdErr().withStdOut(true).exec(cb); + cb.awaitCompletion(); + + return cb.toString().contains("Received status update TASK_FINISHED for task test-cmd"); }); } diff --git a/settings.gradle b/settings.gradle index ea472a58..2a33c995 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,3 +4,4 @@ include "test-framework-docker:scheduler" include "test-framework-docker:executor" include "test-framework-docker:system-test" include "cli" +include "api"