Skip to content
Merged
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
13 changes: 8 additions & 5 deletions src/main/java/controllers/DockerController.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,17 @@ public void restartApp(@PathVariable("name") String name) {
dockerService.restartContainer(name);
}

// **Configure application settings**
@PostMapping("/Config/{id}")
@Operation(summary = "Configure an application", description = "Configures a specific application with the provided parameters.")
@PostMapping("/Config/byName/{name}")
@Operation(
summary = "Configure an application",
description = "Allows adding, updating, or deleting environment variables of a container. The JSON body must contain `add`, `update`, and/or `delete` keys."
)
@Tag(name = "Configuration")
public ResponseEntity<String> configApp(@PathVariable("id") String id, @RequestBody Map<String, String> config) {
return dockerService.configApp(id, config);
public ResponseEntity<String> configAppByName(@PathVariable("name") String name, @RequestBody Map<String, Object> config) {
return dockerService.configApp(name, config);
}


@PutMapping("IsCrash/{name}")
@Operation(summary = "Check application crash status", description = "Checks whether a specific application has crashed.")
@Tag(name = "Crash Status and Errors")
Expand Down
59 changes: 40 additions & 19 deletions src/main/java/services/DockerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.github.dockerjava.api.command.*;
import com.github.dockerjava.api.model.*;
import model.ContainerRunParam;
import org.apache.catalina.Host;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -16,6 +15,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.*;

@Service
public class DockerService {
Expand Down Expand Up @@ -150,34 +150,55 @@ public List<String> listCrashedContainers() {
.toList();
}

// Applique une nouvelle configuration d'environnement (redéploiement)
public ResponseEntity<String> configApp(String id, Map<String, String> conf) {
public ResponseEntity<String> configApp(String name, Map<String, Object> conf) {
try {
Map<String, String> envMap = new HashMap<>();

var inspect = dockerClient.inspectContainerCmd(id).exec();
ContainerRunParam params = new ContainerRunParam(
inspect.getName(),
inspect.getNetworkSettings().getPorts().toString(),
conf,
inspect.getImageId(),
null,
null
);
InspectContainerResponse container = dockerClient.inspectContainerCmd(name).exec();

if ("running".equals(dockerClient.inspectContainerCmd(id).exec().getState().getStatus())) {
dockerClient.stopContainerCmd(id).exec();
}
String[] oldEnvList = container.getConfig().getEnv();
if (oldEnvList != null) {
for (String env : oldEnvList) {
String[] parts = env.split("=", 2);
if (parts.length == 2) {
envMap.put(parts[0], parts[1]);
}
}
}

Map<String, String> toAdd = (Map<String, String>) conf.getOrDefault("add", Map.of());
Map<String, String> toUpdate = (Map<String, String>) conf.getOrDefault("update", Map.of());
Map<String, String> toDelete = (Map<String, String>) conf.getOrDefault("delete", Map.of());

toAdd.forEach(envMap::put);
toUpdate.forEach(envMap::put);
toDelete.keySet().forEach(envMap::remove);

ContainerRunParam params = new ContainerRunParam(
container.getName().replace("/", ""), // le nom avec '/' à retirer
container.getNetworkSettings().getPorts().toString(),
envMap,
container.getImageId(),
null,
null
);

if ("running".equals(container.getState().getStatus())) {
dockerClient.stopContainerCmd(name).exec();
}
dockerClient.removeContainerCmd(name).exec();

System.out.println("Variables finales envoyées à Docker : " + params.getEnv());

dockerClient.removeContainerCmd(id).exec();
try {
startImage(params);
return ResponseEntity.ok(id);
return ResponseEntity.ok(name);

} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Error: " + e.getMessage());
}
}


/// Image management

public String pullImage(String imageName) throws InterruptedException {
Expand Down
104 changes: 104 additions & 0 deletions src/test/java/org/example/jafeur/ConfigTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package org.example.jafeur;

import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.InspectContainerResponse;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import services.DockerService;

import java.util.*;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ConfigTests {

@Autowired
private DockerService dockerService;

private final DockerClient dockerClient;

@Autowired
public ConfigTests(DockerClient dockerClient) {
this.dockerClient = dockerClient;
}

@BeforeAll
static void setUpBeforeAll() {
System.out.println("Starting ConfigTests...");
}

@AfterAll
static void tearDownAfterAll() {
System.out.println("Finished ConfigTests.");
}

@Test
@Order(1)
void testConfigApp_AddUpdateDeleteEnvVars() throws InterruptedException {
String containerName = "config-test-container";

// 🔁 Supprimer s'il existe déjà
dockerService.getAllContainers().stream()
.filter(container -> Arrays.asList(container.getNames()).contains("/" + containerName))
.findFirst()
.ifPresent(existing -> {
try {
dockerClient.removeContainerCmd(existing.getId()).withForce(true).exec();
System.out.println("Conteneur existant supprimé");
} catch (Exception e) {
fail("Could not remove existing container: " + e.getMessage());
}
});

// 🚀 1. Créer le conteneur initial
CreateContainerResponse created = dockerClient.createContainerCmd("alpine")
.withName(containerName)
.withEnv("INITIAL_VAR=initial")
.withCmd("sh", "-c", "env && sleep 9999")
.exec();
dockerClient.startContainerCmd(created.getId()).exec();
System.out.println("Conteneur initial lancé");

Thread.sleep(500);

// ➕ 2. Ajout des variables
dockerService.configApp(containerName, Map.of(
"add", Map.of("VAR1", "value1", "VAR2", "toremove")
));

Thread.sleep(1000);

InspectContainerResponse afterAdd = dockerClient.inspectContainerCmd(containerName).exec();
String[] rawEnvsAfterAdd = afterAdd.getConfig().getEnv();
assertNotNull(rawEnvsAfterAdd, "Env list is null after add");

List<String> envsAfterAdd = Arrays.asList(rawEnvsAfterAdd);
System.out.println("Env après ajout : " + envsAfterAdd);

assertTrue(envsAfterAdd.contains("VAR1=value1"), "VAR1=value1 n'est pas présent");
assertTrue(envsAfterAdd.contains("VAR2=toremove"), "VAR2=toremove n'est pas présent");

// 🔁 3. Update + Delete
dockerService.configApp(containerName, Map.of(
"update", Map.of("VAR1", "updated-value"),
"delete", Map.of("VAR2", "")
));

Thread.sleep(1000);

InspectContainerResponse afterUpdate = dockerClient.inspectContainerCmd(containerName).exec();
String[] rawEnvsAfterUpdate = afterUpdate.getConfig().getEnv();
assertNotNull(rawEnvsAfterUpdate, "Env list is null after update");

List<String> envsAfterUpdate = Arrays.asList(rawEnvsAfterUpdate);
System.out.println("Env après update : " + envsAfterUpdate);

assertTrue(envsAfterUpdate.contains("VAR1=updated-value"), "VAR1 n'est pas mis à jour");
assertFalse(envsAfterUpdate.stream().anyMatch(e -> e.startsWith("VAR2=")), "VAR2 aurait dû être supprimé");
}

}
17 changes: 0 additions & 17 deletions src/test/java/org/example/jafeur/ContainerTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,23 +80,6 @@ void testGetAllContainers() {
assertNotNull(dockerService.getAllContainers());
}

@Test
@Order(5)
void testConfigApp() {
String containerName = "test-container";
dockerService.configApp(containerName, Map.of("VAR_TEST", "new_value", "VAR_TEST2", "new_value2"));

InspectContainerResponse containerInfo = dockerClient.inspectContainerCmd(containerName).exec();
List<String> envVariables = Arrays.asList(Objects.requireNonNull(containerInfo.getConfig().getEnv()));

assertTrue(envVariables.contains("VAR_TEST=new_value"));
assertTrue(envVariables.contains("VAR_TEST2=new_value2"));

// assert that the container is still running
assertTrue(dockerService.getRunningContainers().stream()
.anyMatch(container -> container.getNames()[0].equals("/" + containerName)));
}

@Test
@Order(6)
void testStopContainer() {
Expand Down