Skip to content

Commit

Permalink
✨ : add stop job
Browse files Browse the repository at this point in the history
  • Loading branch information
cdubuisson committed Jun 18, 2019
1 parent b755279 commit c14ce7d
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 11 deletions.
9 changes: 2 additions & 7 deletions src/main/java/io/codeka/gaia/bo/StackState.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,8 @@ public enum StackState {
TO_UPDATE,

/**
* When the stack has been destroyed
* When the stack has been stopped
*/
DESTROYED,

/**
* When the stack is not visible anaymore
*/
ARCHIVED
STOPPED

}
26 changes: 26 additions & 0 deletions src/main/java/io/codeka/gaia/controller/StackController.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,30 @@ public Job getJob(@PathVariable String stackId, @PathVariable String jobId){
return this.stackRunner.getJob(jobId);
}

@GetMapping("/stacks/{stackId}/stop")
public String stopStack(@PathVariable String stackId, Model model){
// checking if the stack exists
// TODO throw an exception (404) if not
if(stackRepository.existsById(stackId)){
model.addAttribute("stackId", stackId);
}

// create a new job
var job = new Job();
job.setId(UUID.randomUUID().toString());
job.setStackId(stackId);
job.setDateTime(LocalDateTime.now());

model.addAttribute("jobId", job.getId());

// get the stack
var stack = this.stackRepository.findById(stackId).get();
// get the module
var module = this.terraformModuleRepository.findById(stack.getModuleId()).get();

this.stackRunner.stop(job, module, stack);

return "job";
}

}
53 changes: 53 additions & 0 deletions src/main/java/io/codeka/gaia/runner/StackCommandBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,41 @@ String buildPlanScript(Stack stack, TerraformModule module){
return String.join("\n", commands.toArray(new String[]{}));
}

/**
* builds the terraform destroy script
* @return
*/
String buildDestroyScript(Stack stack, TerraformModule module){
var backendGenCommand = String.format("echo \"terraform {\n" +
" backend \\\"http\\\" {\n" +
"\t\taddress=\\\""+settings.getExternalUrl()+"/api/state/%s\\\"\n" +
"\t}\n" +
"}\n\" > backend.tf", stack.getId());

String destroyCommand = buildDestroyCommand(stack, module);

System.out.println(destroyCommand);

var commands = new LinkedList<>(List.of(
"set -ex",
String.format("git clone %s module", module.getGitRepositoryUrl()),
"cd module"));

if(module.getDirectory() != null && !module.getDirectory().isBlank()) {
commands.add(String.format("cd %s", module.getDirectory()));
}

commands.addAll(List.of(
"echo 'generating backend configuration'",
backendGenCommand,
"cat backend.tf",
"terraform version",
"terraform init",
destroyCommand));

return String.join("\n", commands.toArray(new String[]{}));
}

String buildApplyCommand(Stack stack, TerraformModule module) {
var varFormatString = "-var \"%s=%s\" ";
var variablesBuilder = new StringBuilder();
Expand Down Expand Up @@ -129,4 +164,22 @@ String buildPlanCommand(Stack stack, TerraformModule module) {
return String.format("terraform plan -detailed-exitcode %s", variablesBuilder.toString());
}

String buildDestroyCommand(Stack stack, TerraformModule module) {
var varFormatString = "-var \"%s=%s\" ";
var variablesBuilder = new StringBuilder();

module.getVariables().forEach(terraformVariable -> {

var name = terraformVariable.getName();
String value = terraformVariable.getDefaultValue();
// try getting the value from the stack
if(stack.getVariableValues().containsKey(name)){
value = stack.getVariableValues().get(name);
}
variablesBuilder.append(String.format(varFormatString, name, value));
});

return String.format("terraform destroy --auto-approve %s", variablesBuilder.toString());
}

}
32 changes: 32 additions & 0 deletions src/main/java/io/codeka/gaia/runner/StackRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,36 @@ public Job getJob(String jobId) {
// or find in repository
return this.jobRepository.findById(jobId).get();
}

/**
* Runs a "stop job".
* A stop job runs a 'terraform destroy'
* @param job
* @param module
* @param stack
*/
@Async
public void stop(Job job, TerraformModule module, Stack stack) {
this.jobs.put(job.getId(), job);
job.start();

var destroyScript = stackCommandBuilder.buildDestroyScript(stack, module);

var result = runContainerForJob(job, destroyScript);

if(result == 0){
job.end();
// update state
stack.setState(StackState.STOPPED);
stackRepository.save(stack);
} else{
// error
job.fail();
}

// save job to database
jobRepository.save(job);
this.jobs.remove(job.getId());
}

}
7 changes: 4 additions & 3 deletions src/main/resources/templates/stack.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@
<div class="full">
<div class="page_title">
<a href="#" class="btn btn-primary" @click="save"><i class="far fa-save"></i> Save</a>
<a :href="'/stacks/' + stack.id + '/apply'" v-if="stack.state === 'NEW'" class="btn btn-primary"><i class="fas fa-rocket"></i> Run</a>
<a :href="'/stacks/' + stack.id + '/apply'" v-if="stack.state === 'NEW' || stack.state === 'STOPPED'" class="btn btn-primary"><i class="fas fa-rocket"></i> Run</a>
<a :href="'/stacks/' + stack.id + '/apply'" v-if="stack.state === 'TO_UPDATE'" class="btn btn-warning"><i class="fas fa-upload"></i> Update</a>

<a :href="'/stacks/' + stack.id + '/preview'" v-if="stack.state === 'NEW' || stack.state === 'TO_UPDATE'" class="btn btn-info"><i class="fas fa-binoculars"></i> Preview</a>
<a :href="'/stacks/' + stack.id + '/preview'" v-if="stack.state !== 'RUNNING'" class="btn btn-info"><i class="fas fa-binoculars"></i> Preview</a>

<a :href="'/stacks/' + stack.id + '/stop'" v-if="stack.state === 'RUNNING' || stack.state === 'TO_UPDATE'" class="btn btn-danger"><i class="fas fa-stop-circle"></i> Stop</a>
</div>
</div>
</div>
Expand Down Expand Up @@ -92,7 +93,7 @@ <h2>
<span class="badge badge-pill badge-success" v-if="stack.state === 'NEW'" data-toggle="tooltip" title="Your stack is new and has not been started yet."><i class="fas fa-star-of-life"></i> new</span>
<span class="badge badge-pill badge-primary" v-if="stack.state === 'RUNNING'" data-toggle="tooltip" title="Your stack is up and running !"><i class="far fa-check-square"></i> running</span>
<span class="badge badge-pill badge-warning" v-if="stack.state === 'TO_UPDATE'" data-toggle="tooltip" title="Your stack needs an update !"><i class="fas fa-upload"></i> to update</span>
<span class="badge badge-pill badge-danger" v-if="stack.state === 'DESTROYED'" data-toggle="tooltip" title="Your stack has been destroyed."><i class="fas fa-snowplow"></i> destroyed</span>
<span class="badge badge-pill badge-danger" v-if="stack.state === 'STOPPED'" data-toggle="tooltip" title="Your stack has been stopped."><i class="fas fa-stop-circle"></i> stopped</span>
</h2>
</div>
<div class="block_content">
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/templates/stacks.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ <h4>
<span class="badge badge-pill badge-success" v-if="stack.state === 'NEW'" data-toggle="tooltip" title="Your stack is new and has not been started yet."><i class="fas fa-star-of-life"></i> new</span>
<span class="badge badge-pill badge-primary" v-if="stack.state === 'RUNNING'" data-toggle="tooltip" title="Your stack is up and running !"><i class="far fa-check-square"></i> running</span>
<span class="badge badge-pill badge-warning" v-if="stack.state === 'TO_UPDATE'" data-toggle="tooltip" title="Your stack needs an update !"><i class="fas fa-upload"></i> to update</span>
<span class="badge badge-pill badge-danger" v-if="stack.state === 'DESTROYED'" data-toggle="tooltip" title="Your stack has been destroyed."><i class="fas fa-snowplow"></i> destroyed</span>
<span class="badge badge-pill badge-danger" v-if="stack.state === 'STOPPED'" data-toggle="tooltip" title="Your stack has been stopped."><i class="fas fa-stop-circle"></i> stopped</span>
</h4>
<a :href="'/stacks/' + stack.id" data-toggle="tooltip" title="Edit this stack" class="btn btn-primary"><i class="far fa-edit"></i></a>
</div>
Expand Down
26 changes: 26 additions & 0 deletions src/test/java/io/codeka/gaia/runner/StackCommandBuilderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,32 @@ void buildPlanScript_shouldGenerateAFullScript_forAModuleWithoutDirectory(){
assertTrue(script.contains("terraform version\nterraform init\nterraform plan"));
}

@Test
void buildDestroyScript_shouldGenerateAFullScript(){
var stackCommandBuilder = new StackCommandBuilder(new Settings());

TerraformModule module = moduleWithDirectory();

var stack = new Stack();
var script = stackCommandBuilder.buildDestroyScript(stack, module);

assertTrue(script.contains("git clone git://test module\ncd module\ncd directory\necho 'generating backend configuration'"));
assertTrue(script.contains("terraform version\nterraform init\nterraform destroy"));
}

@Test
void buildDestroyScript_shouldGenerateAFullScript_forAModuleWithoutDirectory(){
var stackCommandBuilder = new StackCommandBuilder(new Settings());

TerraformModule module = moduleWithoutDirectory();

var stack = new Stack();
var script = stackCommandBuilder.buildDestroyScript(stack, module);

assertTrue(script.contains("git clone git://test module\ncd module\necho 'generating backend configuration'"));
assertTrue(script.contains("terraform version\nterraform init\nterraform destroy"));
}

@NotNull
private TerraformModule moduleWithDirectory() {
var module = new TerraformModule();
Expand Down

0 comments on commit c14ce7d

Please sign in to comment.