From fc4368d886275544e99c6c834bea8e74d9f3f714 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Majdan?= <445519@mail.muni.cz>
Date: Tue, 13 Aug 2024 12:24:47 +0200
Subject: [PATCH] Resolve "adjust sandbox-service api calls"

---
 VERSION.txt                                   |  1 +
 .../TrainingInstancesRestController.java      | 26 +++++++++++++++++++
 .../domain/training/TrainingInstance.java     |  5 ++++
 .../facade/TrainingInstanceFacade.java        | 24 ++++++++++++-----
 .../training/TrainingInstanceRepository.java  |  8 ++++++
 .../service/api/SandboxServiceApi.java        | 11 +++++---
 .../training/TrainingInstanceService.java     | 11 ++++++++
 .../service/training/TrainingRunService.java  |  2 +-
 8 files changed, 77 insertions(+), 11 deletions(-)

diff --git a/VERSION.txt b/VERSION.txt
index 0c38bdaf..51cfa716 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1,3 +1,4 @@
+2.3.0 Add training access tokens to sandbox api calls.
 2.2.10 Fix user ref creation failing on parallel requests.
 2.2.9 Add check to prevent reviving an expired training instance.
 2.2.8 Add check for training definition being in use when trying to add, remove and update tasks.
diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/controller/TrainingInstancesRestController.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/controller/TrainingInstancesRestController.java
index c39917f8..6034f7d7 100644
--- a/src/main/java/cz/muni/ics/kypo/training/adaptive/controller/TrainingInstancesRestController.java
+++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/controller/TrainingInstancesRestController.java
@@ -86,6 +86,32 @@ public class TrainingInstancesRestController {
         return ResponseEntity.ok(trainingInstanceResource);
     }
 
+    /**
+     * Get requested Training Instance by pool id.
+     *
+     * @param poolId     id of the assigned pool.
+     * @return Requested Training Instance by pool id.
+     */
+    @ApiOperation(httpMethod = "GET",
+            value = "Get training instance by pool id.",
+            response = TrainingInstanceDTO.class,
+            nickname = "findTrainingInstanceByPoolId",
+            notes = "Returns training instance by pool id.",
+            produces = MediaType.APPLICATION_JSON_VALUE
+    )
+    @ApiResponses(value = {
+            @ApiResponse(code = 200, message = "The training instance has been found", response = TrainingInstanceDTO.class),
+            @ApiResponse(code = 404, message = "The training instance has not been found.", response = ApiError.class),
+            @ApiResponse(code = 500, message = "Unexpected condition was encountered.", response = ApiError.class)
+    })
+    @GetMapping(path = "/pool/{poolId}", produces = MediaType.APPLICATION_JSON_VALUE)
+    public ResponseEntity<Object> findTrainingInstanceByPoolId(
+            @ApiParam(value = "Pool ID", required = true)
+            @PathVariable("poolId") Long poolId) {
+        TrainingInstanceDTO trainingInstanceResource = trainingInstanceFacade.findByPoolId(poolId);
+        return ResponseEntity.ok(trainingInstanceResource);
+    }
+
     /**
      * Get all Training Instances.
      *
diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingInstance.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingInstance.java
index 85f30671..7a03dc31 100644
--- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingInstance.java
+++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingInstance.java
@@ -57,6 +57,11 @@ import java.util.Set;
                         "LEFT OUTER JOIN FETCH td.authors " +
                         "WHERE ti.id = :instanceId"
         ),
+        @NamedQuery(
+                name = "TrainingInstance.findByPoolId",
+                query = "SELECT ti FROM TrainingInstance ti " +
+                        "WHERE ti.poolId = :poolId"
+        ),
         @NamedQuery(
                 name = "TrainingInstance.findAllByTrainingDefinitionId",
                 query = "SELECT ti FROM TrainingInstance ti JOIN FETCH ti.trainingDefinition td WHERE td.id = :trainingDefId"
diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingInstanceFacade.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingInstanceFacade.java
index 69c07477..51141490 100644
--- a/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingInstanceFacade.java
+++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingInstanceFacade.java
@@ -106,6 +106,18 @@ public class TrainingInstanceFacade {
         return trainingInstanceMapper.mapToDTO(trainingInstanceService.findByIdIncludingDefinition(id));
     }
 
+    /**
+     * Finds specific Training Instance by pool id
+     *
+     * @param poolId ID of a pool
+     * @return specific {@link TrainingInstanceDTO} by pool id
+     */
+    @IsOrganizerOrAdmin
+    @TransactionalRO
+    public TrainingInstanceDTO findByPoolId(Long poolId) {
+        return trainingInstanceMapper.mapToDTO(trainingInstanceService.findByPoolId(poolId));
+    }
+
     /**
      * Find all Training Instances.
      *
@@ -145,21 +157,21 @@ public class TrainingInstanceFacade {
         Long oldPoolId = trainingInstance.getPoolId();
         String accessToken = trainingInstanceService.update(updatedTrainingInstance);
         if (isPoolIdChanged(oldPoolId, updatedTrainingInstance.getPoolId())) {
-            handlePoolIdModification(oldPoolId, updatedTrainingInstance.getPoolId());
+            handlePoolIdModification(oldPoolId, updatedTrainingInstance.getPoolId(), updatedTrainingInstance.getAccessToken());
         }
         return accessToken;
     }
 
-    private void handlePoolIdModification(Long currentPoolId, Long newPoolId) {
+    private void handlePoolIdModification(Long currentPoolId, Long newPoolId, String accessToken) {
         if (currentPoolId == null) {
-            sandboxServiceApi.lockPool(newPoolId);
+            sandboxServiceApi.lockPool(newPoolId, accessToken);
         } else if (newPoolId == null) {
             sandboxServiceApi.unlockPool(currentPoolId);
             deleteBashCommandsByPool(currentPoolId);
         } else {
             sandboxServiceApi.unlockPool(currentPoolId);
             deleteBashCommandsByPool(currentPoolId);
-            sandboxServiceApi.lockPool(newPoolId);
+            sandboxServiceApi.lockPool(newPoolId, accessToken);
         }
     }
 
@@ -182,7 +194,7 @@ public class TrainingInstanceFacade {
         trainingInstance.setId(null);
         TrainingInstance createdTrainingInstance = trainingInstanceService.create(trainingInstance);
         if (trainingInstance.getPoolId() != null) {
-            handlePoolIdModification(null, trainingInstance.getPoolId());
+            handlePoolIdModification(null, trainingInstance.getPoolId(), trainingInstance.getAccessToken());
         }
         return trainingInstanceMapper.mapToDTO(createdTrainingInstance);
     }
@@ -282,7 +294,7 @@ public class TrainingInstanceFacade {
                     "Training instance already contains pool Id. Please first unassign pool id and then assign another pool again."));
         }
         // lock pool and update pool
-        sandboxServiceApi.lockPool(trainingInstanceAssignPoolIdDTO.getPoolId());
+        sandboxServiceApi.lockPool(trainingInstanceAssignPoolIdDTO.getPoolId(), trainingInstance.getAccessToken());
         trainingInstance.setPoolId(trainingInstanceAssignPoolIdDTO.getPoolId());
         return trainingInstanceMapper.mapEntityToTIBasicInfo(trainingInstanceService.auditAndSave(trainingInstance));
     }
diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/training/TrainingInstanceRepository.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/training/TrainingInstanceRepository.java
index 22235368..50172720 100644
--- a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/training/TrainingInstanceRepository.java
+++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/training/TrainingInstanceRepository.java
@@ -76,6 +76,14 @@ public interface TrainingInstanceRepository extends JpaRepository<TrainingInstan
     )
     Optional<TrainingInstance> findById(Long id);
 
+    /**
+     * Find training instance by pool id.
+     *
+     * @param poolId the pool id
+     * @return {@link TrainingInstance} including its associated {@link TrainingDefinition}
+     */
+    Optional<TrainingInstance> findByPoolId(@Param("poolId") Long poolId);
+
     /**
      * Find training instance with start time in the past, end time in the future and by corresponding access token.
      *
diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/api/SandboxServiceApi.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/api/SandboxServiceApi.java
index 68fa0c65..8503ba6d 100644
--- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/api/SandboxServiceApi.java
+++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/api/SandboxServiceApi.java
@@ -37,11 +37,11 @@ public class SandboxServiceApi {
     }
 
 
-    public Pair<Integer, String> getAndLockSandboxForTrainingRun(Long poolId) {
+    public Pair<Integer, String> getAndLockSandboxForTrainingRun(Long poolId, String trainingAccessToken) {
         try {
             SandboxInfo sandboxInfo = sandboxServiceWebClient
                     .get()
-                    .uri("/pools/{poolId}/sandboxes/get-and-lock", poolId)
+                    .uri("/pools/{poolId}/sandboxes/get-and-lock/{trainingAccessToken}", poolId, trainingAccessToken)
                     .retrieve()
                     .bodyToMono(SandboxInfo.class)
                     .block();
@@ -58,14 +58,17 @@ public class SandboxServiceApi {
      * Lock pool locked pool info.
      *
      * @param poolId the pool id
+     * @param accessToken the training access token
      * @return the locked pool info
      */
-    public LockedPoolInfo lockPool(Long poolId) {
+    public LockedPoolInfo lockPool(Long poolId, String accessToken) {
         try {
+            String requestBody = String.format("{\"training_access_token\": \"%s\"}", accessToken);
+
             return sandboxServiceWebClient
                     .post()
                     .uri("/pools/{poolId}/locks", poolId)
-                    .body(Mono.just("{}"), String.class)
+                    .body(Mono.just(requestBody), String.class)
                     .retrieve()
                     .bodyToMono(LockedPoolInfo.class)
                     .block();
diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java
index 68c04fba..d9b70dd5 100644
--- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java
+++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java
@@ -74,6 +74,17 @@ public class TrainingInstanceService {
                 .orElseThrow(() -> new EntityNotFoundException(new EntityErrorDetail(TrainingInstance.class, "id", instanceId.getClass(), instanceId)));
     }
 
+    /**
+     * Find specific Training instance by pool id.
+     *
+     * @param poolId the pool id
+     * @return the {@link TrainingInstance}
+     */
+    public TrainingInstance findByPoolId(Long poolId) {
+        return trainingInstanceRepository.findByPoolId(poolId)
+                .orElseThrow(() -> new EntityNotFoundException(new EntityErrorDetail(TrainingInstance.class, "poolId", poolId.getClass(), poolId)));
+    }
+
     /**
      * Find specific Training instance by id including its associated Training definition.
      *
diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java
index b4b955ae..e226d8c1 100644
--- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java
+++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java
@@ -610,7 +610,7 @@ public class TrainingRunService {
      * @throws MicroserviceApiException error calling OpenStack Sandbox Service API
      */
     public TrainingRun assignSandbox(TrainingRun trainingRun, long poolId) {
-        Pair<Integer, String> sandboxRefAndId = this.sandboxServiceApi.getAndLockSandboxForTrainingRun(poolId);
+        Pair<Integer, String> sandboxRefAndId = this.sandboxServiceApi.getAndLockSandboxForTrainingRun(poolId, trainingRun.getTrainingInstance().getAccessToken());
         trainingRun.setSandboxInstanceRefId(sandboxRefAndId.getRight());
         trainingRun.setSandboxInstanceAllocationId(sandboxRefAndId.getLeft());
         return trainingRunRepository.save(trainingRun);
-- 
GitLab