Skip to content

Commit

Permalink
πŸ”€ Merge pull request #127 from CodeKaio/62-job-details
Browse files Browse the repository at this point in the history
♻️ : rework of the job management
  • Loading branch information
juwit authored Aug 30, 2019
2 parents 41d2f80 + 9b40b8d commit e7fd764
Show file tree
Hide file tree
Showing 48 changed files with 2,808 additions and 753 deletions.
98 changes: 98 additions & 0 deletions src/main/java/io/codeka/gaia/runner/DockerRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package io.codeka.gaia.runner;

import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.exceptions.DockerException;
import com.spotify.docker.client.messages.ContainerConfig;
import io.codeka.gaia.settings.bo.Settings;
import io.codeka.gaia.stacks.workflow.JobWorkflow;
import org.apache.commons.io.output.WriterOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;

/**
* Service to run docker container
*/
@Service
public class DockerRunner {

private static final Logger LOG = LoggerFactory.getLogger(DockerRunner.class);

private DockerClient dockerClient;
private ContainerConfig.Builder containerConfigBuilder;
private HttpHijackWorkaround httpHijackWorkaround;
private Settings settings;

@Autowired
public DockerRunner(DockerClient dockerClient, ContainerConfig.Builder containerConfigBuilder,
HttpHijackWorkaround httpHijackWorkaround, Settings settings) {
this.dockerClient = dockerClient;
this.containerConfigBuilder = containerConfigBuilder;
this.httpHijackWorkaround = httpHijackWorkaround;
this.settings = settings;
}

int runContainerForJob(JobWorkflow jobWorkflow, String script) {
try {
var env = new ArrayList<String>();
env.add("TF_IN_AUTOMATION=true");
env.addAll(settings.env());

var job = jobWorkflow.getJob();

// FIXME This is certainly no thread safe !
var containerConfig = containerConfigBuilder
.env(env)
.image("hashicorp/terraform:" + job.getCliVersion())
.build();

// pull the image
dockerClient.pull("hashicorp/terraform:" + job.getCliVersion());

var containerCreation = dockerClient.createContainer(containerConfig);
var containerId = containerCreation.id();

var dockerContainer = new DockerContainer(containerId, dockerClient, httpHijackWorkaround);

dockerClient.startContainer(containerId);

// attaching the outputs in a background thread
var step = jobWorkflow.getCurrentStep();
CompletableFuture.runAsync(() -> {
try (var writerOutputStream = new WriterOutputStream(step.getLogsWriter(), Charset.defaultCharset())) {
// this code is blocking I/O !
dockerContainer.attach(writerOutputStream, writerOutputStream);
} catch (IOException | StackRunnerException e) {
LOG.error("Unable to attach logs of container", e);
}
});

// write the content of the script to the container's std in
try (WritableByteChannel stdIn = Channels.newChannel(dockerContainer.getStdIn())) {
stdIn.write(ByteBuffer.wrap(script.getBytes()));
}

// wait for the container to exit
var containerExit = dockerClient.waitContainer(containerCreation.id());

dockerClient.removeContainer(containerCreation.id());

return Math.toIntExact(containerExit.statusCode());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return 99;
} catch (DockerException | IOException | StackRunnerException e) {
return 99;
}
}

}
30 changes: 25 additions & 5 deletions src/main/java/io/codeka/gaia/runner/StackCommandBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ private String buildCommand(Stack stack, TerraformModule module, String command)
return String.format("%s %s", command, variablesBuilder.toString());
}

/**
* builds the terraform plan script
*
* @return
*/
String buildPlanScript(Stack stack, TerraformModule module) {
return buildScript(stack, module, this::buildPlanCommand);
}

/**
* builds the terraform apply script
*
Expand All @@ -84,8 +93,8 @@ String buildApplyScript(Stack stack, TerraformModule module) {
*
* @return
*/
String buildPlanScript(Stack stack, TerraformModule module) {
return buildScript(stack, module, this::buildPlanCommand);
String buildPlanDestroyScript(Stack stack, TerraformModule module) {
return buildScript(stack, module, this::buildPlanDestroyCommand);
}

/**
Expand All @@ -97,6 +106,17 @@ String buildDestroyScript(Stack stack, TerraformModule module) {
return buildScript(stack, module, this::buildDestroyCommand);
}

/**
* builds the terraform plan command
*
* @param stack
* @param module
* @return
*/
String buildPlanCommand(Stack stack, TerraformModule module) {
return buildCommand(stack, module, "terraform plan -detailed-exitcode");
}

/**
* builds the terraform apply command
*
Expand All @@ -109,14 +129,14 @@ String buildApplyCommand(Stack stack, TerraformModule module) {
}

/**
* builds the terraform plan command
* builds the terraform plan destroy command
*
* @param stack
* @param module
* @return
*/
String buildPlanCommand(Stack stack, TerraformModule module) {
return buildCommand(stack, module, "terraform plan -detailed-exitcode");
String buildPlanDestroyCommand(Stack stack, TerraformModule module) {
return buildCommand(stack, module, "terraform plan -destroy -detailed-exitcode");
}

/**
Expand Down
Loading

0 comments on commit e7fd764

Please sign in to comment.