Skip to content
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
27 changes: 23 additions & 4 deletions build-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,32 @@
<artifactId>jetty-webapp</artifactId>
<version>${jetty.version}</version>
</dependency>
<!--Needed for the Stateless annotation that hibernate validator needs-->
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>ejb-api</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>${resteasy.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-simple</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>


<!-- Utilities -->

<!--We use the shaded artifact to minimalise conflicts between jersey and RestEasy-->
<dependency>
<groupId>com.spotify</groupId>
<artifactId>docker-client</artifactId>
<version>2.7.19</version>
<groupId>com.spotify</groupId>
<artifactId>docker-client</artifactId>
<classifier>shaded</classifier>
<version>8.3.2</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public ObjectMapper get() {
});

bind(DockerClient.class).toInstance(DefaultDockerClient.fromEnv()
.readTimeoutMillis(DefaultDockerClient.NO_TIMEOUT)
.readTimeoutMillis(0)
.build());

findResourcesWith(Path.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import com.google.inject.Singleton;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.DockerClient.AttachParameter;
import com.spotify.docker.client.DockerException;
import com.spotify.docker.client.LogStream;
import com.spotify.docker.client.exceptions.DockerException;
import com.spotify.docker.client.messages.ContainerConfig;
import com.spotify.docker.client.messages.ContainerCreation;
import com.spotify.docker.client.messages.ContainerExit;
Expand Down Expand Up @@ -268,7 +268,10 @@ public ContainerExit call() throws Exception {
BuildInstruction buildInstruction = buildRequest.getInstruction();
buildInstructionInterpreter.runPluginBefores(buildInstruction, stagingDirectory);

final HostConfig hostConfig = HostConfig.builder().binds(volume).build();

ContainerConfig.Builder configBuilder = ContainerConfig.builder()
.hostConfig(hostConfig)
.image(buildInstructionInterpreter.getImage(buildInstruction))
.cmd(buildInstructionInterpreter.getCommand(buildInstruction).split(" "))
.user(config.getDockerUser())
Expand All @@ -283,7 +286,8 @@ public ContainerExit call() throws Exception {
id = creation.id();
containerId.set(id);
log.info("Starting container {}", id);
dockerClient.startContainer(id, HostConfig.builder().binds(volume).build());
dockerClient.startContainer(id);

}
catch (DockerException | InterruptedException e) {
logger.println("[FATAL] Failed to provision build environment");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.Response.StatusType;

import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.util.Base64;

import com.google.common.base.Strings;
Expand Down Expand Up @@ -72,7 +72,7 @@ public void onSuccess(BuildResult result) {
log.info("Returning build results to callback URL: {}",
buildRequest.getCallbackUrl());
for (int i = 0; i <= 4; i++) {
Client client = ClientBuilder.newClient();
Client client = new ResteasyClientBuilder().build();
try {
Response response = prepareCallback(client).post(
Entity.json(result));
Expand Down
1 change: 1 addition & 0 deletions build-server/src/main/resources/config.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ authorization.client-id = MichaelLaptop
authorization.client-secret = t2hLCXVE

docker.max-containers = 3

docker.staging-directory = /workspace
docker.working-directory = /workspace
docker.user = root
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,54 @@
package com.spotify.docker.client;

import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.Queue;

import org.apache.commons.io.input.NullInputStream;

public class MockedLogStream extends LogStream {
public class MockedLogStream implements LogStream {

private final Queue<LogMessage> logMessages;

public MockedLogStream() {
super(new NullInputStream(0));
this.logMessages = new LinkedList<LogMessage>();
}
public void addMessage(final LogMessage message) {
logMessages.add(message);
}

@Override
protected LogMessage computeNext() {
if (logMessages.isEmpty())
return endOfData();
return logMessages.remove();
public String readFully() {
return "";
}

public void addMessage(final LogMessage message) {
logMessages.add(message);
@Override
public void attach(OutputStream stdout, OutputStream stderr) throws IOException {

}


@Override
public void attach(OutputStream stdout, OutputStream stderr, boolean closeAtEof) throws IOException {

}

@Override
public void close() {
try {
super.close();
}
catch (Throwable t) {}
}

@Override
public boolean hasNext() {
return !logMessages.isEmpty();
}

@Override
public LogMessage next() {
return logMessages.remove();
}

@Override
public void remove() {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import com.google.common.io.Files;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.DockerClient.AttachParameter;
import com.spotify.docker.client.DockerException;

import com.spotify.docker.client.MockedLogStream;
import com.spotify.docker.client.exceptions.DockerException;
import com.spotify.docker.client.messages.ContainerConfig;
import com.spotify.docker.client.messages.ContainerCreation;
import com.spotify.docker.client.messages.ContainerExit;
Expand Down Expand Up @@ -56,11 +57,15 @@ public class BuildManagerTest {

public static final int CONCURRENT_JOBS = 3;

@Mock private Config config;
@Mock private DockerClient dockerClient;
@InjectMocks private MavenBuildInstructionInterpreter mavenBuildInstructionInterpreter;
@Mock private GitStagingDirectoryPreparer gitStagingDirectoryPreparer;

@Mock
private Config config;
@Mock
private DockerClient dockerClient;
@InjectMocks
private MavenBuildInstructionInterpreter mavenBuildInstructionInterpreter;
@Mock
private GitStagingDirectoryPreparer gitStagingDirectoryPreparer;

private BuildManager manager;

private static File stagingDirectory;
Expand All @@ -75,18 +80,18 @@ public static void createTempDir() {
public void setUp() throws DockerException, InterruptedException {
when(config.getMaximumConcurrentJobs()).thenReturn(CONCURRENT_JOBS);
when(config.getStagingDirectory()).thenReturn(stagingDirectory.getAbsolutePath());

when(dockerClient.createContainer(Mockito.any(ContainerConfig.class), Mockito.anyString()))
.thenReturn(new ContainerCreation(UUID.randomUUID().toString()));
.thenReturn(ContainerCreation.builder().id(UUID.randomUUID().toString()).build());
when(dockerClient.attachContainer(Mockito.anyString(), Mockito.<AttachParameter>anyVararg()))
.thenReturn(new MockedLogStream());
when(dockerClient.waitContainer(Mockito.anyString())).thenReturn(new ContainerExit(0));
when(dockerClient.waitContainer(Mockito.anyString())).thenReturn(ContainerExit.create(0));

manager = new BuildManager(config, dockerClient,
new StagingDirectoryPreparerRegistry(gitStagingDirectoryPreparer),
new BuildInstructionInterpreterRegistry(mavenBuildInstructionInterpreter));
}

@After
public void tearDown() {
manager.lifeCycleStopping(null);
Expand Down Expand Up @@ -133,7 +138,7 @@ public void testThatJobCanBeScheduledWhenCapacityIsRestored() throws Interrupted
for (int i = 0; i < CONCURRENT_JOBS; i++) {
uuid = manager.schedule(createRequest()).getUUID();
}

assertNotNull(uuid);
manager.killBuild(uuid);
assertNotNull(manager.schedule(createRequest()));
Expand All @@ -144,21 +149,21 @@ public void testThatJobCanBeScheduledWhenCapacityIsRestoredThroughTermination()
for (int i = 0; i < CONCURRENT_JOBS - 1; i++) {
manager.schedule(createRequest());
}

UUID scheduled = manager.schedule(createRequest()).getUUID();
assertNotNull(scheduled);

Thread.sleep(100);
assertNotNull(scheduled);
}

@Test
public void waitForABuild() throws InterruptedException, ExecutionException {
Build result = manager.schedule(createRequest());
log.info("Result : {}", result.get());
}
@Test(timeout=2000) // kill test after 2 seconds

@Test(timeout = 2000) // kill test after 2 seconds
public void testBuildWithTimeout() throws DockerException, InterruptedException, ExecutionException {
BuildRequest buildRequest = createRequest();
buildRequest.setTimeout(1); // timeout 1 second
Expand All @@ -177,7 +182,7 @@ private void setContainerExitDuration(final long duration) throws DockerExceptio
public ContainerExit answer(InvocationOnMock invocation)
throws Throwable {
Thread.sleep(duration); // sleep 20 seconds
return new ContainerExit(0);
return ContainerExit.create(0);
}

});
Expand All @@ -187,7 +192,7 @@ public ContainerExit answer(InvocationOnMock invocation)
public void testOldRequestSupport() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModules(new MappingModule());
try(InputStream in = BuildManagerTest.class.getResourceAsStream("/build-requests/java-maven-old.json")) {
try (InputStream in = BuildManagerTest.class.getResourceAsStream("/build-requests/java-maven-old.json")) {
BuildRequest request = objectMapper.readValue(in, BuildRequest.class);
Build resultFuture = manager.schedule(request);
BuildResult result = resultFuture.get();
Expand All @@ -199,24 +204,24 @@ public void testOldRequestSupport() throws Exception {
public void testNewRequestSupport() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModules(new MappingModule());
try(InputStream in = BuildManagerTest.class.getResourceAsStream("/build-requests/java-maven-new.json")) {
try (InputStream in = BuildManagerTest.class.getResourceAsStream("/build-requests/java-maven-new.json")) {
BuildRequest request = objectMapper.readValue(in, BuildRequest.class);
Build resultFuture = manager.schedule(request);
BuildResult result = resultFuture.get();
assertEquals(Status.SUCCEEDED, result.getStatus());
}
}

private BuildRequest createRequest() {
GitSource source = new GitSource();
source.setBranchName("master");
source.setRepositoryUrl("https://github.com/devhub-tud/build-server.git");
source.setCommitId("2625eaf9b476dd158ad5f9cad3d5137f3b111ea7");

MavenBuildInstruction instruction = new MavenBuildInstruction();
instruction.setPhases(new String[] { "package" });
instruction.setPhases(new String[]{"package"});
instruction.setWithDisplay(true);

BuildRequest request = new BuildRequest();
request.setSource(source);
request.setInstruction(instruction);
Expand Down
27 changes: 21 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
<packaging>pom</packaging>

<properties>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

<guice.version>3.0</guice.version>
<hibernate.version>4.2.7.Final</hibernate.version>
<jackson.version>2.3.0</jackson.version>
<resteasy.version>3.0.4.Final</resteasy.version>
<jackson.version>2.6.3</jackson.version>
<resteasy.version>3.0.19.Final</resteasy.version>
<slf4j.version>1.7.5</slf4j.version>
</properties>

Expand Down Expand Up @@ -48,7 +48,22 @@
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-hibernatevalidator-provider</artifactId>
<version>${resteasy.version}</version>
<!--We exclude weld because it had conflicts with the ByteStreams in guava-->
<exclusions>
<exclusion>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se</artifactId>
</exclusion>
</exclusions>
</dependency>

<!--However the annotations of weld were a implicit transitive dependency so we re add them here.-->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.2</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-guava</artifactId>
Expand Down Expand Up @@ -103,7 +118,7 @@
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.8</version>
<version>0.9.9</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
Expand All @@ -113,7 +128,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>15.0</version>
<version>18.0</version>
</dependency>
</dependencies>

Expand Down