Skip to content
This repository was archived by the owner on Jun 22, 2018. It is now read-only.

WIP #456 Added initial api module #457

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM containersol/alpine3.3-java8-jre:v1
MAINTAINER Container Solutions BV <[email protected]>

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
127 changes: 127 additions & 0 deletions api/build.gradle
Original file line number Diff line number Diff line change
@@ -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
67 changes: 67 additions & 0 deletions api/src/main/java/com/containersol/minimesos/api/ApiServer.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.containersol.minimesos.api;

public class ClusterStartedResponse {

private String clusterId;

public ClusterStartedResponse(String clusterId) {
this.clusterId = clusterId;
}
}
15 changes: 15 additions & 0 deletions api/src/main/java/com/containersol/minimesos/api/JsonUtils.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
14 changes: 14 additions & 0 deletions api/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<configuration debug="false">

<appender name="JAVA" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<logger name="com.containersol.minimesos.api" level="info">
<appender-ref ref="JAVA"/>
</logger>

</configuration>
Original file line number Diff line number Diff line change
@@ -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<String> response = Unirest.get(apiServer.getServiceUrl() + "/info").asString();

assertEquals("No cluster is running", response.getBody());
}

@Test
public void testStart() throws UnirestException, IOException {
HttpResponse<String> 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<String> 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());
}

}
54 changes: 54 additions & 0 deletions api/src/test/resources/minimesosFile-apiServer
Original file line number Diff line number Diff line change
@@ -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"
}
}
Original file line number Diff line number Diff line change
@@ -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";
}
}
Loading