diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f96fe1b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: + push: + branches: + - '**' + pull_request: + branches: + - main + +jobs: + test: + name: Test Code + runs-on: ubuntu-latest + steps: + - name: Clone repo + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: 'maven' + + - name: Set up Docker + uses: docker/setup-buildx-action@v2 + + - name: Start services with Docker Compose + run: | + docker compose up -d --build + + - name: Run tests + run: | + mvn clean test + + - name: Stop and clean up Docker Compose + if: always() + run: | + docker compose down \ No newline at end of file diff --git a/pom.xml b/pom.xml index 24f0bc4..3de8489 100644 --- a/pom.xml +++ b/pom.xml @@ -56,15 +56,6 @@ 2.5.0 - - org.postgresql - postgresql - runtime - - - org.springframework.boot - spring-boot-starter-data-jpa - org.projectlombok lombok diff --git a/src/main/java/config/DockerConfig.java b/src/main/java/config/DockerConfig.java index f53b463..d6e8dba 100644 --- a/src/main/java/config/DockerConfig.java +++ b/src/main/java/config/DockerConfig.java @@ -14,10 +14,12 @@ public class DockerConfig { @Bean public DockerClient dockerClient() { + // Configure la connexion au démon Docker local via le socket Unix var config = DefaultDockerClientConfig.createDefaultConfigBuilder() .withDockerHost("unix:///var/run/docker.sock") .build(); + // Crée un client HTTP pour communiquer avec l’API Docker var httpClient = new OkDockerHttpClient.Builder() .dockerHost(config.getDockerHost()) .sslConfig(config.getSSLConfig()) diff --git a/src/main/java/controllers/DockerController.java b/src/main/java/controllers/DockerController.java index d78e6ff..0932be0 100644 --- a/src/main/java/controllers/DockerController.java +++ b/src/main/java/controllers/DockerController.java @@ -26,7 +26,6 @@ public DockerController(DockerService dockerService) { this.dockerService = dockerService; } - // **Change application status (start, stop, restart)** @PutMapping("/Start/{name}") @Operation(summary = "Start a specific application", description = "Starts a specific application by its name.") @Tag(name = "Change Status") @@ -63,7 +62,6 @@ public ResponseEntity configApp(@PathVariable("id") String id, @RequestB return dockerService.configApp(id, config); } - // **Check crash status** @PutMapping("IsCrash/{name}") @Operation(summary = "Check application crash status", description = "Checks whether a specific application has crashed.") @Tag(name = "Crash Status and Errors") @@ -131,6 +129,7 @@ public ResponseEntity startImage(@RequestBody ContainerRunParam params) @Tag(name = "Retrieve Information") public ResponseEntity> getContainers(@PathVariable Boolean showAll) { try { + // Renvoie soit tous les conteneurs, soit uniquement ceux en cours d'exécution List containers; if (showAll) { containers = dockerService.getAllContainers(); diff --git a/src/main/java/org/example/jafeur/JaFeurApplication.java b/src/main/java/org/example/jafeur/JaFeurApplication.java index 71a9ebc..77e9704 100644 --- a/src/main/java/org/example/jafeur/JaFeurApplication.java +++ b/src/main/java/org/example/jafeur/JaFeurApplication.java @@ -4,12 +4,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.annotation.ComponentScan; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @SpringBootApplication -@ComponentScan(basePackages = {"org.example.jafeur", "controllers", "repositories", "services", "config"}) +@ComponentScan(basePackages = {"org.example.jafeur", "controllers", "services", "config"}) @EntityScan(basePackages = {"model"}) -@EnableJpaRepositories(basePackages = {"repositories"}) public class JaFeurApplication { public static void main(String[] args) { diff --git a/src/main/java/services/DockerService.java b/src/main/java/services/DockerService.java index 692a4d9..ca146c3 100644 --- a/src/main/java/services/DockerService.java +++ b/src/main/java/services/DockerService.java @@ -4,6 +4,7 @@ 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; @@ -149,16 +150,19 @@ public List listCrashedContainers() { .toList(); } + // Applique une nouvelle configuration d'environnement (redéploiement) public ResponseEntity configApp(String id, Map conf) { + var inspect = dockerClient.inspectContainerCmd(id).exec(); ContainerRunParam params = new ContainerRunParam( - dockerClient.inspectContainerCmd(id).exec().getName(), - dockerClient.inspectContainerCmd(id).exec().getNetworkSettings().getPorts().toString(), + inspect.getName(), + inspect.getNetworkSettings().getPorts().toString(), conf, - dockerClient.inspectContainerCmd(id).exec().getImageId(), + inspect.getImageId(), null, null ); + if ("running".equals(dockerClient.inspectContainerCmd(id).exec().getState().getStatus())) { dockerClient.stopContainerCmd(id).exec(); } @@ -198,35 +202,17 @@ public String buildDockerfile(String tag, Path path) { .awaitImageId(); } + // Lance un conteneur avec les paramètres nécessaires (env, volume, traefik) public String startImage(ContainerRunParam params) { CreateContainerCmd containerBuilder = dockerClient.createContainerCmd(params.getImage()); - // Définir le nom du conteneur if (params.getName() != null) { containerBuilder.withName(params.getName()); } - // Générer un port basé sur l'ID (évite conflits) -// int defaultPort = 80; // Port interne de l'app -// int hostPort = generatePortFromName(params.getName()); // Port unique basé sur le nom -// -// // Exposer le port -// ExposedPort exposedPort = ExposedPort.tcp(defaultPort); -// HostConfig hostConfig = new HostConfig() -// .withPortBindings(new PortBinding(Ports.Binding.bindPort(hostPort), exposedPort)); -// -//// Appliquer d'abord l'exposition des ports, puis le HostConfig -// containerBuilder -// .withExposedPorts(exposedPort) -// .withHostConfig(hostConfig); // Appliquer la config après - containerBuilder .withExposedPorts(ExposedPort.tcp(80)); - // .withHostConfig(new HostConfig().withNetworkMode("web")); // <-- le réseau Docker partagé avec Traefik // enlevé car bugs pour les tests - - - // Ajouter les variables d'environnement if (params.getEnv() != null) { List env = new ArrayList<>(); for (Map.Entry entry : params.getEnv().entrySet()) { @@ -235,18 +221,17 @@ public String startImage(ContainerRunParam params) { containerBuilder.withEnv(env); } - // Ajouter le volume si défini if (params.getVolume() != null) { containerBuilder.withVolumes(new Volume(params.getVolume())); } - // Ajouter une commande spécifique si définie if (params.getCommand() != null) { containerBuilder.withCmd(params.getCommand()); } - // Ajouter les labels pour Traefik/Nginx - containerBuilder.withLabels(Map.of( + // Configuration des labels pour exposer l'app via Traefik + containerBuilder.withHostConfig(new HostConfig().withNetworkMode("traefik-network")) + .withLabels(Map.of( "traefik.enable", "true", "traefik.http.routers." + params.getName() + ".rule", "Host(`jafeur-" + params.getName() + ".localhost`)", "traefik.http.routers." + params.getName() + ".entrypoints", "web", @@ -254,19 +239,12 @@ public String startImage(ContainerRunParam params) { )); - // Exécuter la création du conteneur CreateContainerResponse container = containerBuilder.exec(); dockerClient.startContainerCmd(container.getId()).exec(); return "Container " + params.getName() + " started! Accessible at http://jafeur-" + params.getName() + ".localhost"; } - private int generatePortFromName(String name) { - int hash = name.hashCode(); - int basePort = 10000; // Évite conflits avec ports système - return basePort + (Math.abs(hash) % 50000); // Ports entre 10000 et 60000 - } - public void removeImage(String imageId) { dockerClient.removeImageCmd(imageId).exec(); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 83fbbbf..160e4a2 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,6 +1,2 @@ spring.application.name=JaFeur springdoc.swagger-ui.path=/swagger - -spring.datasource.url=jdbc:postgresql://162.38.112.137:5432/ -spring.datasource.username=postgres -spring.datasource.password=feur \ No newline at end of file