This is an automated email from the ASF dual-hosted git repository.

dyankiv pushed a commit to branch DATALAB-2648
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git


The following commit(s) were added to refs/heads/DATALAB-2648 by this push:
     new 21fea4270 add support for terminating user image
21fea4270 is described below

commit 21fea427071fca74d845059aae7dfddada92ace0
Author: Denys Yankiv <[email protected]>
AuthorDate: Thu Aug 25 17:44:37 2022 +0300

    add support for terminating user image
---
 .../epam/datalab/dto/exploratory/ImageStatus.java  |  2 ++
 .../datalab/rest/contracts/ExploratoryAPI.java     |  1 +
 .../backendapi/core/commands/DockerAction.java     |  1 +
 .../backendapi/resources/ImageResource.java        | 13 +++++++++
 .../backendapi/dao/ImageExploratoryDAO.java        |  2 ++
 .../backendapi/dao/ImageExploratoryDAOImpl.java    |  7 +++++
 .../resources/ImageExploratoryResource.java        | 22 +++++++++------
 .../resources/callback/ImageCallback.java          | 10 +++++--
 .../service/ImageExploratoryService.java           |  4 +++
 .../service/impl/ImageExploratoryServiceImpl.java  | 33 ++++++++++++++++++++--
 .../main/resources/mongo/general/mongo_roles.json  | 12 ++++++++
 11 files changed, 94 insertions(+), 13 deletions(-)

diff --git 
a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageStatus.java
 
b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageStatus.java
index fb2133aaf..80ec6f0cc 100644
--- 
a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageStatus.java
+++ 
b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageStatus.java
@@ -26,6 +26,8 @@ import java.util.Arrays;
 public enum ImageStatus {
     CREATING,
     ACTIVE,
+    TERMINATING,
+    TERMINATED,
     FAILED;
 
     @JsonCreator
diff --git 
a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ExploratoryAPI.java
 
b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ExploratoryAPI.java
index d153a15f7..bce4eb29a 100644
--- 
a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ExploratoryAPI.java
+++ 
b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ExploratoryAPI.java
@@ -31,4 +31,5 @@ public interface ExploratoryAPI {
     String EXPLORATORY_LIB_LIST = LIBRARY + EXPLORATORY + "/lib_list";
     String EXPLORATORY_GIT_CREDS = EXPLORATORY + "/git_creds";
     String EXPLORATORY_IMAGE = EXPLORATORY + "/image";
+    String EXPLORATORY_IMAGE_TERMINATE = EXPLORATORY + "/image" + "/terminate";
 }
diff --git 
a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerAction.java
 
b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerAction.java
index d61bac680..a801aefc0 100644
--- 
a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerAction.java
+++ 
b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerAction.java
@@ -32,6 +32,7 @@ public enum DockerAction {
        LIB_INSTALL,
        GIT_CREDS,
        CREATE_IMAGE,
+    TERMINATE_IMAGE,
        STATUS,
     REUPLOAD_KEY,
     RECONFIGURE_SPARK,
diff --git 
a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ImageResource.java
 
b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ImageResource.java
index b565556b1..1e4347431 100644
--- 
a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ImageResource.java
+++ 
b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ImageResource.java
@@ -59,6 +59,19 @@ public class ImageResource extends DockerService implements 
DockerCommands {
         return Response.accepted(uuid).build();
     }
 
+    @POST
+    @Path("/terminate")
+    public Response terminateImage(@Auth UserInfo ui, ExploratoryImageDTO 
image) throws JsonProcessingException{
+        final String uuid = DockerCommands.generateUUID();
+        log.info("terminate image dto {}",image);
+
+        folderListenerExecutor.start(configuration.getImagesDirectory(), 
configuration.getResourceStatusPollTimeout(),
+                new ImageCreateCallbackHandler(selfService, uuid, 
DockerAction.TERMINATE_IMAGE, image));
+        String command = 
commandBuilder.buildCommand(getDockerCommand(DockerAction.TERMINATE_IMAGE, 
uuid, image), image);
+        commandExecutor.executeAsync(ui.getName(), uuid, command);
+        log.debug("Docker command: " + command);
+        return Response.accepted(uuid).build();
+    }
 
     @Override
     public String getResourceType() {
diff --git 
a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAO.java
 
b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAO.java
index 4b67166b6..be068d546 100644
--- 
a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAO.java
+++ 
b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAO.java
@@ -36,6 +36,8 @@ public interface ImageExploratoryDAO {
 
     void updateImageFields(Image image);
 
+    void updateImageStatus(String user, String imageName, String project, 
String endpoint, ImageStatus status);
+
     List<ImageInfoRecord> getImages(String user, String dockerImage, String 
project, String endpoint, ImageStatus... statuses);
 
     List<ImageInfoRecord> getImages(String project, String endpoint, String 
dockerImage);
diff --git 
a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAOImpl.java
 
b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAOImpl.java
index d4fde8042..b52c35010 100644
--- 
a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAOImpl.java
+++ 
b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAOImpl.java
@@ -42,6 +42,7 @@ import static com.mongodb.client.model.Projections.elemMatch;
 import static com.mongodb.client.model.Projections.excludeId;
 import static com.mongodb.client.model.Projections.fields;
 import static com.mongodb.client.model.Projections.include;
+import static com.mongodb.client.model.Updates.set;
 
 @Singleton
 public class ImageExploratoryDAOImpl extends BaseDAO implements 
ImageExploratoryDAO {
@@ -72,6 +73,12 @@ public class ImageExploratoryDAOImpl extends BaseDAO 
implements ImageExploratory
         updateOne(MongoCollections.IMAGES, condition, new Document(SET, 
updatedFields));
     }
 
+    @Override
+    public void updateImageStatus(String user, String imageName, String 
project, String endpoint, ImageStatus status) {
+        final Bson condition = userImageCondition(user, imageName, project, 
endpoint);
+        updateOne(MongoCollections.IMAGES, condition, 
set(STATUS,status.toString()));
+    }
+
     @Override
     public List<ImageInfoRecord> getImages(String user, String dockerImage, 
String project, String endpoint, ImageStatus... statuses) {
         return find(MongoCollections.IMAGES,
diff --git 
a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ImageExploratoryResource.java
 
b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ImageExploratoryResource.java
index 3c7085ec5..1950b224e 100644
--- 
a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ImageExploratoryResource.java
+++ 
b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ImageExploratoryResource.java
@@ -27,15 +27,10 @@ import com.google.inject.Inject;
 import io.dropwizard.auth.Auth;
 import lombok.extern.slf4j.Slf4j;
 
+import javax.annotation.security.RolesAllowed;
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
+import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -129,8 +124,19 @@ public class ImageExploratoryResource {
     @Path("share")
     public Response shareImageWithProjectGroups(@Auth UserInfo ui, @Valid 
@NotNull ImageProjectGroupsShareDTO dto) {
         log.debug("Sharing user image {} with project {} groups", 
dto.getImageName(), dto.getProjectName());
-        imageExploratoryService.shareImageWithProjectGroups(ui, 
dto.getImageName(), dto.getProjectName(),  dto.getEndpoint());
+        imageExploratoryService.shareImageWithProjectGroups(ui, 
dto.getImageName(), dto.getProjectName(), dto.getEndpoint());
         return 
Response.ok(imageExploratoryService.getImagesOfUser(ui)).build();
     }
 
+    @RolesAllowed("/api/image/terminate")
+    @DELETE
+    @Path("/{projectName}/{endpoint}/{imageName}/terminate")
+    public Response terminateUserImage(@Auth UserInfo ui,
+                                       @PathParam("imageName") String 
imageName,
+                                       @PathParam("projectName") String 
projectName,
+                                       @PathParam("endpoint") String endpoint) 
{
+        log.debug("Terminating  image {} of user {} groups", imageName, 
ui.getName());
+        
imageExploratoryService.terminateImage(ui,projectName,endpoint,imageName);
+        return 
Response.ok(imageExploratoryService.getImagesOfUser(ui)).build();
+    }
 }
diff --git 
a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ImageCallback.java
 
b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ImageCallback.java
index 587c8ea41..d66d550f3 100644
--- 
a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ImageCallback.java
+++ 
b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ImageCallback.java
@@ -51,8 +51,14 @@ public class ImageCallback {
     public Response imageCreateStatus(ImageCreateStatusDTO dto) {
         log.debug("Updating status of image {} for user {} to {}", 
dto.getName(), dto.getUser(), dto);
         requestId.remove(dto.getRequestId());
-        imageExploratoryService.finishImageCreate(getImage(dto), 
dto.getExploratoryName(), dto.getImageCreateDTO()
-                .getIp());
+
+        
if(dto.getStatus().equalsIgnoreCase(String.valueOf(ImageStatus.TERMINATED))){
+            
imageExploratoryService.finishTerminateImage(dto.getImageCreateDTO().getExternalName());
+        } else {
+            imageExploratoryService.finishImageCreate(getImage(dto), 
dto.getExploratoryName(), dto.getImageCreateDTO()
+                    .getIp());
+        }
+
         return Response.status(Response.Status.CREATED).build();
     }
 
diff --git 
a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ImageExploratoryService.java
 
b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ImageExploratoryService.java
index b07a83616..889aa8f44 100644
--- 
a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ImageExploratoryService.java
+++ 
b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ImageExploratoryService.java
@@ -32,6 +32,10 @@ public interface ImageExploratoryService {
 
     String createImage(UserInfo user, String project, String exploratoryName, 
String imageName, String imageDescription, String info);
 
+    void terminateImage(UserInfo user, String project, String endpoint, String 
imageName);
+
+    void finishTerminateImage(String fullImageName);
+
     void finishImageCreate(Image image, String exploratoryName, String 
newNotebookIp);
 
     List<ImageInfoRecord> getNotFailedImages(UserInfo user, String 
dockerImage, String project, String endpoint);
diff --git 
a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImpl.java
 
b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImpl.java
index ee2e83677..691800e8d 100644
--- 
a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImpl.java
+++ 
b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImpl.java
@@ -60,6 +60,7 @@ import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 import static com.epam.datalab.backendapi.domain.AuditActionEnum.CREATE;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.TERMINATE;
 import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.IMAGE;
 
 @Singleton
@@ -69,7 +70,7 @@ public class ImageExploratoryServiceImpl implements 
ImageExploratoryService {
     private static final String IMAGE_NOT_FOUND_MSG = "Image with name %s was 
not found for user %s";
 
     private static final String SHARE_OWN_IMAGES_PAGE = "/api/image/share";
-    private static final String TERMINATE_OWN_IMAGES_PAGE = 
"/api/image/delete";
+    private static final String TERMINATE_OWN_IMAGES_PAGE = 
"/api/image/terminate";
     private static final String SHARE_RECEIVED_IMAGES_PAGE = 
"/api/image/shareReceived";
     private static final String IMAGE_ROLE = "img_%s_%s_%s_%s";
     private static final String IMAGE_ROLE_DESCRIPTION = "Create Notebook from 
image %s";
@@ -143,6 +144,30 @@ public class ImageExploratoryServiceImpl implements 
ImageExploratoryService {
                 requestBuilder.newExploratoryImageCreate(user, userInstance, 
imageName, endpointDTO, projectDTO), String.class);
     }
 
+    @Audit(action = TERMINATE, type = IMAGE)
+    @Override
+    public void terminateImage(@User UserInfo user, @Project String project, 
String endpoint, String imageName) {
+        Optional<ImageInfoRecord> image = 
imageExploratoryDao.getImage(user.getName(), imageName, project, endpoint);
+        if(image.isPresent()){
+            ImageInfoRecord imageInfoRecord = image.get();
+            
imageExploratoryDao.updateImageStatus(user.getName(),imageName,project,endpoint,ImageStatus.TERMINATING);
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            ProjectDTO projectDTO = projectService.get(project);
+            UserInstanceDTO userInstance = 
exploratoryDAO.fetchExploratoryFields(user.getName(), project, 
imageInfoRecord.getInstanceName());
+
+            log.info("ExploratoryImageCreate {}", 
requestBuilder.newExploratoryImageCreate(user, userInstance, imageName, 
endpointDTO, projectDTO));
+            provisioningService.post(endpointDTO.getUrl() + 
ExploratoryAPI.EXPLORATORY_IMAGE_TERMINATE,
+                    user.getAccessToken(), 
requestBuilder.newExploratoryImageCreate(user, userInstance, imageName, 
endpointDTO, projectDTO)
+                    , String.class);
+        }
+
+    }
+
+    @Override
+    public void finishTerminateImage(String fullImageName) {
+
+    }
+
     @Override
     public void finishImageCreate(Image image, String exploratoryName, String 
newNotebookIp) {
         log.debug("Returning exploratory status with name {} to RUNNING for 
user {}",
@@ -325,16 +350,18 @@ public class ImageExploratoryServiceImpl implements 
ImageExploratoryService {
     @Override
     public ImageUserPermissions getUserImagePermissions(UserInfo userInfo, 
ImageInfoRecord image) {
         boolean canShare;
-        boolean canTerminate = false;
+        boolean canTerminate;
 
         if(!image.getStatus().equals(ImageStatus.ACTIVE)){
-            return new ImageUserPermissions(false,canTerminate);
+            return new ImageUserPermissions(false,false);
         }
 
         if(image.getUser().equals(userInfo.getName())){
             canShare = UserRoles.checkAccess(userInfo, RoleType.PAGE, 
SHARE_OWN_IMAGES_PAGE,userInfo.getRoles());
+            canTerminate = UserRoles.checkAccess(userInfo, RoleType.PAGE, 
TERMINATE_OWN_IMAGES_PAGE,userInfo.getRoles());
         } else {
             canShare = UserRoles.checkAccess(userInfo, RoleType.PAGE, 
SHARE_RECEIVED_IMAGES_PAGE,userInfo.getRoles());
+            canTerminate = false;
         }
         return new ImageUserPermissions(canShare,canTerminate);
     }
diff --git 
a/services/self-service/src/main/resources/mongo/general/mongo_roles.json 
b/services/self-service/src/main/resources/mongo/general/mongo_roles.json
index b4c7d25b4..fd5ca0b08 100644
--- a/services/self-service/src/main/resources/mongo/general/mongo_roles.json
+++ b/services/self-service/src/main/resources/mongo/general/mongo_roles.json
@@ -24,6 +24,18 @@
       "$anyuser"
     ]
   },
+  {
+    "_id": "imgTerminateOwnImages",
+    "description": "Allow to terminate own images",
+    "type": "IMAGE",
+    "cloud": "GENERAL",
+    "pages": [
+      "/api/image/terminate"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
   {
     "_id": "nbBillingReportFull",
     "description": "View full billing report for all users",


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to