You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dlab.apache.org by of...@apache.org on 2020/06/10 09:52:41 UTC

[incubator-dlab] 02/07: Added audit support for notebooks

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

ofuks pushed a commit to branch audit
in repository https://gitbox.apache.org/repos/asf/incubator-dlab.git

commit 809fa372b7744c5b987b4190d2caad40f3704546
Author: Oleh Fuks <ol...@gmail.com>
AuthorDate: Thu Jun 4 16:54:09 2020 +0300

    Added audit support for notebooks
---
 .../java/com/epam/dlab/util/UsernameUtils.java     |   2 +-
 .../dlab/backendapi/domain/AuditActionEnum.java    |   3 +-
 .../backendapi/interceptor/AuditInterceptor.java   |   2 +-
 .../backendapi/resources/ExploratoryResource.java  |   8 +-
 .../backendapi/service/ExploratoryService.java     |   8 +-
 .../service/impl/EnvironmentServiceImpl.java       |  17 ++-
 .../service/impl/ExploratoryServiceImpl.java       | 108 ++++++++-------
 .../service/impl/ProjectServiceImpl.java           |   4 +-
 .../service/impl/SchedulerJobServiceImpl.java      |  12 +-
 .../epam/dlab/backendapi/util/RequestBuilder.java  |  82 +++++------
 .../resources/ExploratoryResourceTest.java         | 150 ++++++++++-----------
 .../service/impl/EnvironmentServiceImplTest.java   |  24 ++--
 .../service/impl/ExploratoryServiceImplTest.java   |  84 ++++++------
 .../service/impl/SchedulerJobServiceImplTest.java  |  20 +--
 14 files changed, 270 insertions(+), 254 deletions(-)

diff --git a/services/dlab-utils/src/main/java/com/epam/dlab/util/UsernameUtils.java b/services/dlab-utils/src/main/java/com/epam/dlab/util/UsernameUtils.java
index 32488a4..9622661 100644
--- a/services/dlab-utils/src/main/java/com/epam/dlab/util/UsernameUtils.java
+++ b/services/dlab-utils/src/main/java/com/epam/dlab/util/UsernameUtils.java
@@ -24,7 +24,7 @@ public class UsernameUtils {
 	private static final String UNDERLINE = "_";
 
 	public static String removeDomain(String username) {
-		return username.replaceAll("@.*", "");
+		return username != null ? username.replaceAll("@.*", "") : null;
 	}
 
 	public static String replaceWhitespaces(String username) {
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditActionEnum.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditActionEnum.java
index 7a02a79..431e0c7 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditActionEnum.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditActionEnum.java
@@ -20,5 +20,6 @@
 package com.epam.dlab.backendapi.domain;
 
 public enum AuditActionEnum {
-    CREATE_PROJECT, START_PROJECT, STOP_PROJECT, TERMINATE_PROJECT, UPDATE_PROJECT
+    CREATE_PROJECT, START_PROJECT, STOP_PROJECT, TERMINATE_PROJECT, UPDATE_PROJECT,
+    CREATE_NOTEBOOK, START_NOTEBOOK, STOP_NOTEBOOK, TERMINATE_NOTEBOOK, UPDATE_CLUSTER_CONFIG
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/AuditInterceptor.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/AuditInterceptor.java
index 20a42d7..713e587 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/AuditInterceptor.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/AuditInterceptor.java
@@ -92,7 +92,7 @@ public class AuditInterceptor implements MethodInterceptor {
 
     private List<String> getInfo(MethodInvocation mi, Parameter[] parameters) {
         return IntStream.range(0, parameters.length)
-                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(Info.class)))
+                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(Info.class)) && Objects.nonNull(mi.getArguments()[i]))
                 .mapToObj(i -> (List<String>) mi.getArguments()[i])
                 .findAny()
                 .orElseGet(Collections::emptyList);
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ExploratoryResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ExploratoryResource.java
index 7b29af1..a9b176c 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ExploratoryResource.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ExploratoryResource.java
@@ -86,7 +86,7 @@ public class ExploratoryResource implements ExploratoryAPI {
 			log.warn("Unauthorized attempt to create a {} by user {}", formDTO.getImage(), userInfo.getName());
 			throw new DlabException("You do not have the privileges to create a " + formDTO.getTemplateName());
 		}
-		String uuid = exploratoryService.create(userInfo, getExploratory(formDTO), formDTO.getProject());
+		String uuid = exploratoryService.create(userInfo, getExploratory(formDTO), formDTO.getProject(), formDTO.getName());
 		return Response.ok(uuid).build();
 
 	}
@@ -105,7 +105,7 @@ public class ExploratoryResource implements ExploratoryAPI {
 						@Valid @NotNull ExploratoryActionFormDTO formDTO) {
 		log.debug("Starting exploratory environment {} for user {}", formDTO.getNotebookInstanceName(),
 				userInfo.getName());
-		return exploratoryService.start(userInfo, formDTO.getNotebookInstanceName(), formDTO.getProjectName());
+		return exploratoryService.start(userInfo, formDTO.getNotebookInstanceName(), formDTO.getProjectName(), null);
 	}
 
 	/**
@@ -121,7 +121,7 @@ public class ExploratoryResource implements ExploratoryAPI {
 					   @PathParam("project") String project,
 					   @PathParam("name") String name) {
 		log.debug("Stopping exploratory environment {} for user {}", name, userInfo.getName());
-		return exploratoryService.stop(userInfo, project, name);
+		return exploratoryService.stop(userInfo, userInfo.getName(), project, name, null);
 	}
 
 	/**
@@ -137,7 +137,7 @@ public class ExploratoryResource implements ExploratoryAPI {
 							@PathParam("project") String project,
 							@PathParam("name") String name) {
 		log.debug("Terminating exploratory environment {} for user {}", name, userInfo.getName());
-		return exploratoryService.terminate(userInfo, project, name);
+		return exploratoryService.terminate(userInfo, userInfo.getName(), project, name, null);
 	}
 
 	@PUT
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ExploratoryService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ExploratoryService.java
index 807df17..7caa8f7 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ExploratoryService.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ExploratoryService.java
@@ -34,13 +34,13 @@ import java.util.Set;
 
 public interface ExploratoryService {
 
-    String start(UserInfo userInfo, String exploratoryName, String project);
+    String start(UserInfo userInfo, String exploratoryName, String project, List<String> auditInfo);
 
-    String stop(UserInfo userInfo, String project, String exploratoryName);
+    String stop(UserInfo userInfo, String resourceCreator, String project, String exploratoryName, List<String> auditInfo);
 
-    String terminate(UserInfo userInfo, String project, String exploratoryName);
+    String terminate(UserInfo userInfo, String resourceCreator, String project, String exploratoryName, List<String> auditInfo);
 
-    String create(UserInfo userInfo, Exploratory exploratory, String project);
+    String create(UserInfo userInfo, Exploratory exploratory, String project, String exploratoryName);
 
     void updateProjectExploratoryStatuses(String project, String endpoint, UserInstanceStatus status);
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java
index 8b2806b..0465171 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java
@@ -44,6 +44,7 @@ import lombok.extern.slf4j.Slf4j;
 
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Stream;
@@ -55,8 +56,9 @@ import static java.util.stream.Collectors.toList;
 @Singleton
 @Slf4j
 public class EnvironmentServiceImpl implements EnvironmentService {
-	private static final String ERROR_MSG_FORMAT = "Can not %s environment because on of user resource is in status " +
-			"CREATING or STARTING";
+	private static final String ERROR_MSG_FORMAT = "Can not %s environment because on of user resource is in status CREATING or STARTING";
+	private static final String AUDIT_QUOTA_MESSAGE = "Billing quota reached";
+	private static final String DLAB_SYSTEM_USER = "DLab system user";
 
 	private final EnvDAO envDAO;
 	private final UserSettingsDAO settingsDAO;
@@ -130,7 +132,8 @@ public class EnvironmentServiceImpl implements EnvironmentService {
 		exploratoryDAO.fetchRunningExploratoryFieldsForProject(project)
 				.forEach(this::stopNotebookWithServiceAccount);
 
-		projectService.get(project).getEndpoints().stream()
+		projectService.get(project).getEndpoints()
+				.stream()
 				.filter(e -> UserInstanceStatus.RUNNING == e.getStatus())
 				.forEach(endpoint -> projectService.stop(securityService.getServiceAccountInfo("admin"),
 						endpoint.getName(), project));
@@ -139,7 +142,7 @@ public class EnvironmentServiceImpl implements EnvironmentService {
 	@ProjectAdmin
 	@Override
 	public void stopExploratory(@User UserInfo userInfo, String user, @Project String project, String exploratoryName) {
-		exploratoryService.stop(new UserInfo(user, userInfo.getAccessToken()), project, exploratoryName);
+		exploratoryService.stop(userInfo, user, project, exploratoryName, null);
 	}
 
 	@ProjectAdmin
@@ -153,7 +156,7 @@ public class EnvironmentServiceImpl implements EnvironmentService {
 	@ProjectAdmin
 	@Override
 	public void terminateExploratory(@User UserInfo userInfo, String user, @Project String project, String exploratoryName) {
-		exploratoryService.terminate(new UserInfo(user, userInfo.getAccessToken()), project, exploratoryName);
+		exploratoryService.terminate(userInfo, user, project, exploratoryName, null);
 	}
 
 	@ProjectAdmin
@@ -182,8 +185,8 @@ public class EnvironmentServiceImpl implements EnvironmentService {
 	}
 
 	private void stopNotebookWithServiceAccount(UserInstanceDTO instance) {
-		final UserInfo userInfo = securityService.getServiceAccountInfo(instance.getUser());
-		exploratoryService.stop(userInfo, instance.getProject(), instance.getExploratoryName());
+		final UserInfo userInfo = securityService.getServiceAccountInfo(DLAB_SYSTEM_USER);
+		exploratoryService.stop(userInfo, instance.getUser(), instance.getProject(), instance.getExploratoryName(), Collections.singletonList(AUDIT_QUOTA_MESSAGE));
 	}
 
 	private List<UserResourceInfo> getProjectEnv(ProjectDTO projectDTO, List<UserInstanceDTO> allInstances) {
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java
index 9f6be91..088bc26 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java
@@ -20,8 +20,12 @@
 package com.epam.dlab.backendapi.service.impl;
 
 import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.annotation.Audit;
 import com.epam.dlab.backendapi.annotation.BudgetLimited;
+import com.epam.dlab.backendapi.annotation.Info;
 import com.epam.dlab.backendapi.annotation.Project;
+import com.epam.dlab.backendapi.annotation.ResourceName;
+import com.epam.dlab.backendapi.annotation.User;
 import com.epam.dlab.backendapi.dao.ComputationalDAO;
 import com.epam.dlab.backendapi.dao.ExploratoryDAO;
 import com.epam.dlab.backendapi.dao.GitCredsDAO;
@@ -41,7 +45,6 @@ import com.epam.dlab.dto.StatusEnvBaseDTO;
 import com.epam.dlab.dto.UserInstanceDTO;
 import com.epam.dlab.dto.UserInstanceStatus;
 import com.epam.dlab.dto.aws.computational.ClusterConfig;
-import com.epam.dlab.dto.computational.UserComputationalResource;
 import com.epam.dlab.dto.exploratory.ExploratoryActionDTO;
 import com.epam.dlab.dto.exploratory.ExploratoryGitCredsDTO;
 import com.epam.dlab.dto.exploratory.ExploratoryReconfigureSparkClusterActionDTO;
@@ -64,6 +67,11 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.CREATE_NOTEBOOK;
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.START_NOTEBOOK;
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.STOP_NOTEBOOK;
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.TERMINATE_NOTEBOOK;
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.UPDATE_CLUSTER_CONFIG;
 import static com.epam.dlab.dto.UserInstanceStatus.CREATING;
 import static com.epam.dlab.dto.UserInstanceStatus.FAILED;
 import static com.epam.dlab.dto.UserInstanceStatus.STARTING;
@@ -80,48 +88,56 @@ import static com.epam.dlab.rest.contracts.ExploratoryAPI.EXPLORATORY_TERMINATE;
 @Slf4j
 @Singleton
 public class ExploratoryServiceImpl implements ExploratoryService {
+	private final ProjectService projectService;
+	private final ExploratoryDAO exploratoryDAO;
+	private final ComputationalDAO computationalDAO;
+	private final GitCredsDAO gitCredsDAO;
+	private final ImageExploratoryDao imageExploratoryDao;
+	private final RESTService provisioningService;
+	private final RequestBuilder requestBuilder;
+	private final RequestId requestId;
+	private final TagService tagService;
+	private final EndpointService endpointService;
 
 	@Inject
-	private ProjectService projectService;
-	@Inject
-	private ExploratoryDAO exploratoryDAO;
-	@Inject
-	private ComputationalDAO computationalDAO;
-	@Inject
-	private GitCredsDAO gitCredsDAO;
-	@Inject
-	private ImageExploratoryDao imageExploratoryDao;
-	@Inject
-	@Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
-	private RESTService provisioningService;
-	@Inject
-	private RequestBuilder requestBuilder;
-	@Inject
-	private RequestId requestId;
-	@Inject
-	private TagService tagService;
-	@Inject
-	private EndpointService endpointService;
+	public ExploratoryServiceImpl(ProjectService projectService, ExploratoryDAO exploratoryDAO, ComputationalDAO computationalDAO, GitCredsDAO gitCredsDAO,
+								  ImageExploratoryDao imageExploratoryDao, @Named(ServiceConsts.PROVISIONING_SERVICE_NAME) RESTService provisioningService,
+								  RequestBuilder requestBuilder, RequestId requestId, TagService tagService, EndpointService endpointService) {
+		this.projectService = projectService;
+		this.exploratoryDAO = exploratoryDAO;
+		this.computationalDAO = computationalDAO;
+		this.gitCredsDAO = gitCredsDAO;
+		this.imageExploratoryDao = imageExploratoryDao;
+		this.provisioningService = provisioningService;
+		this.requestBuilder = requestBuilder;
+		this.requestId = requestId;
+		this.tagService = tagService;
+		this.endpointService = endpointService;
+	}
 
 	@BudgetLimited
+	@Audit(action = START_NOTEBOOK)
 	@Override
-	public String start(UserInfo userInfo, String exploratoryName, @Project String project) {
-		return action(userInfo, project, exploratoryName, EXPLORATORY_START, STARTING);
+	public String start(@User UserInfo userInfo, @ResourceName String exploratoryName, @Project String project, @Info List<String> auditInfo) {
+		return action(userInfo, userInfo.getName(), project, exploratoryName, EXPLORATORY_START, STARTING);
 	}
 
+	@Audit(action = STOP_NOTEBOOK)
 	@Override
-	public String stop(UserInfo userInfo, String project, String exploratoryName) {
-		return action(userInfo, project, exploratoryName, EXPLORATORY_STOP, STOPPING);
+	public String stop(@User UserInfo userInfo, String resourceCreator, String project, @ResourceName String exploratoryName, @Info List<String> auditInfo) {
+		return action(userInfo, resourceCreator, project, exploratoryName, EXPLORATORY_STOP, STOPPING);
 	}
 
+	@Audit(action = TERMINATE_NOTEBOOK)
 	@Override
-	public String terminate(UserInfo userInfo, String project, String exploratoryName) {
-		return action(userInfo, project, exploratoryName, EXPLORATORY_TERMINATE, TERMINATING);
+	public String terminate(@User UserInfo userInfo, String resourceCreator, String project, @ResourceName String exploratoryName, @Info List<String> auditInfo) {
+		return action(userInfo, resourceCreator, project, exploratoryName, EXPLORATORY_TERMINATE, TERMINATING);
 	}
 
 	@BudgetLimited
+	@Audit(action = CREATE_NOTEBOOK)
 	@Override
-	public String create(UserInfo userInfo, Exploratory exploratory, @Project String project) {
+	public String create(@User UserInfo userInfo, Exploratory exploratory, @Project String project, @ResourceName String exploratoryName) {
 		boolean isAdded = false;
 		try {
 			final ProjectDTO projectDTO = projectService.get(project);
@@ -156,8 +172,9 @@ public class ExploratoryServiceImpl implements ExploratoryService {
 				.forEach(ui -> updateExploratoryStatus(project, ui.getExploratoryName(), status, ui.getUser()));
 	}
 
+	@Audit(action = UPDATE_CLUSTER_CONFIG)
 	@Override
-	public void updateClusterConfig(UserInfo userInfo, String project, String exploratoryName, List<ClusterConfig> config) {
+	public void updateClusterConfig(@User UserInfo userInfo, String project, @ResourceName String exploratoryName, List<ClusterConfig> config) {
 		final String userName = userInfo.getName();
 		final String token = userInfo.getAccessToken();
 		final UserInstanceDTO userInstanceDTO = exploratoryDAO.fetchRunningExploratoryFields(userName, project, exploratoryName);
@@ -237,39 +254,32 @@ public class ExploratoryServiceImpl implements ExploratoryService {
 				.collect(Collectors.toList());
 	}
 
-
-	private List<UserComputationalResource> computationalResourcesWithStatus(UserInstanceDTO userInstance,
-																			 UserInstanceStatus computationalStatus) {
-		return userInstance.getResources().stream()
-				.filter(resource -> resource.getStatus().equals(computationalStatus.toString()))
-				.collect(Collectors.toList());
-	}
-
 	/**
 	 * Sends the post request to the provisioning service and update the status of exploratory environment.
 	 *
 	 * @param userInfo        user info.
+	 * @param resourceCreator username of person who has created the resource
 	 * @param project         name of project
 	 * @param exploratoryName name of exploratory environment.
 	 * @param action          action for exploratory environment.
 	 * @param status          status for exploratory environment.
 	 * @return Invocation request as JSON string.
 	 */
-	private String action(UserInfo userInfo, String project, String exploratoryName, String action, UserInstanceStatus status) {
+	private String action(UserInfo userInfo, String resourceCreator, String project, String exploratoryName, String action, UserInstanceStatus status) {
 		try {
-			updateExploratoryStatus(project, exploratoryName, status, userInfo.getName());
+			updateExploratoryStatus(project, exploratoryName, status, resourceCreator);
 
-			UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), project, exploratoryName);
+			UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(resourceCreator, project, exploratoryName);
 			EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
 			final String uuid =
 					provisioningService.post(endpointDTO.getUrl() + action, userInfo.getAccessToken(),
-							getExploratoryActionDto(userInfo, status, userInstance, endpointDTO), String.class);
-			requestId.put(userInfo.getName(), uuid);
+							getExploratoryActionDto(userInfo, resourceCreator, status, userInstance, endpointDTO), String.class);
+			requestId.put(resourceCreator, uuid);
 			return uuid;
 		} catch (Exception t) {
 			log.error("Could not {} exploratory environment {} for user {}",
-					StringUtils.substringAfter(action, "/"), exploratoryName, userInfo.getName(), t);
-			updateExploratoryStatusSilent(userInfo.getName(), project, exploratoryName, FAILED);
+					StringUtils.substringAfter(action, "/"), exploratoryName, resourceCreator, t);
+			updateExploratoryStatusSilent(resourceCreator, project, exploratoryName, FAILED);
 			final String errorMsg = String.format("Could not %s exploratory environment %s: %s",
 					StringUtils.substringAfter(action, "/"), exploratoryName,
 					Optional.ofNullable(t.getCause()).map(Throwable::getMessage).orElse(t.getMessage()));
@@ -289,15 +299,13 @@ public class ExploratoryServiceImpl implements ExploratoryService {
 		}
 	}
 
-	private ExploratoryActionDTO<?> getExploratoryActionDto(UserInfo userInfo, UserInstanceStatus status,
-															UserInstanceDTO userInstance, EndpointDTO endpointDTO) {
+	private ExploratoryActionDTO<?> getExploratoryActionDto(UserInfo userInfo, String resourceCreator, UserInstanceStatus status, UserInstanceDTO userInstance,
+															EndpointDTO endpointDTO) {
 		ExploratoryActionDTO<?> dto;
 		if (status != UserInstanceStatus.STARTING) {
-			dto = requestBuilder.newExploratoryStop(userInfo, userInstance, endpointDTO);
+			dto = requestBuilder.newExploratoryStop(resourceCreator, userInstance, endpointDTO);
 		} else {
-			dto = requestBuilder.newExploratoryStart(
-					userInfo, userInstance, endpointDTO, gitCredsDAO.findGitCreds(userInfo.getName()));
-
+			dto = requestBuilder.newExploratoryStart(userInfo, userInstance, endpointDTO, gitCredsDAO.findGitCreds(userInfo.getName()));
 		}
 		return dto;
 	}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
index 9658897..85cfe85 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
@@ -115,8 +115,8 @@ public class ProjectServiceImpl implements ProjectService {
 	}
 
 	@BudgetLimited
-	@Override
 	@Audit(action = CREATE_PROJECT)
+	@Override
 	public void create(@User UserInfo user, ProjectDTO projectDTO, @ResourceName String resourceName) {
 		if (!projectDAO.get(projectDTO.getName()).isPresent()) {
 			projectDAO.create(projectDTO);
@@ -182,7 +182,7 @@ public class ProjectServiceImpl implements ProjectService {
 						.stream()
 						.map(ProjectEndpointDTO::getName)
 						.collect(Collectors.toList()))
-				.forEach(e -> exploratoryService.stop(new UserInfo(e.getUser(), userInfo.getAccessToken()), projectName, e.getExploratoryName()));
+				.forEach(e -> exploratoryService.stop(userInfo, e.getUser(), projectName, e.getExploratoryName(), null));
 
 		endpointDTOs
 				.stream()
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImpl.java
index cb7b1c1..e00a288 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImpl.java
@@ -51,6 +51,7 @@ import java.time.LocalTime;
 import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
 import java.time.temporal.ChronoUnit;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Objects;
@@ -75,9 +76,8 @@ import static java.util.Date.from;
 @Slf4j
 @Singleton
 public class SchedulerJobServiceImpl implements SchedulerJobService {
-
-	private static final String SCHEDULER_NOT_FOUND_MSG =
-			"Scheduler job data not found for user %s with exploratory %s";
+	private static final String SCHEDULER_NOT_FOUND_MSG = "Scheduler job data not found for user %s with exploratory %s";
+	private static final String AUDIT_MESSAGE = "Scheduled action";
 	private static final long ALLOWED_INACTIVITY_MINUTES = 1L;
 
 	@Inject
@@ -236,7 +236,7 @@ public class SchedulerJobServiceImpl implements SchedulerJobService {
 		final String user = job.getUser();
 		final String project = job.getProject();
 		log.debug("Stopping exploratory {} for user {} by scheduler", expName, user);
-		exploratoryService.stop(securityService.getServiceAccountInfo(user), project, expName);
+		exploratoryService.stop(securityService.getServiceAccountInfo(user), user, project, expName, Collections.singletonList(AUDIT_MESSAGE));
 	}
 
 	private List<SchedulerJobData> getExploratorySchedulersForTerminating(OffsetDateTime now) {
@@ -258,7 +258,7 @@ public class SchedulerJobServiceImpl implements SchedulerJobService {
 		final String exploratoryName = schedulerJobData.getExploratoryName();
 		final String project = schedulerJobData.getProject();
 		log.debug("Starting exploratory {} for user {} by scheduler", exploratoryName, user);
-		exploratoryService.start(securityService.getServiceAccountInfo(user), exploratoryName, project);
+		exploratoryService.start(securityService.getServiceAccountInfo(user), exploratoryName, project, Collections.singletonList(AUDIT_MESSAGE));
 		if (schedulerJobData.getJobDTO().isSyncStartRequired()) {
 			log.trace("Starting computational for exploratory {} for user {} by scheduler", exploratoryName, user);
 			final DataEngineType sparkCluster = DataEngineType.SPARK_STANDALONE;
@@ -277,7 +277,7 @@ public class SchedulerJobServiceImpl implements SchedulerJobService {
 		final String project = job.getProject();
 		final String expName = job.getExploratoryName();
 		log.debug("Terminating exploratory {} for user {} by scheduler", expName, user);
-		exploratoryService.terminate(securityService.getUserInfoOffline(user), project, expName);
+		exploratoryService.terminate(securityService.getUserInfoOffline(user), user, project, expName, Collections.singletonList(AUDIT_MESSAGE));
 	}
 
 	private void startSpark(String user, String expName, String compName, String project) {
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/RequestBuilder.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/util/RequestBuilder.java
index afe06cd..32bea28 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/RequestBuilder.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/util/RequestBuilder.java
@@ -96,38 +96,38 @@ public class RequestBuilder {
 	@Inject
 	private SettingsDAO settingsDAO;
 
-	private CloudSettings cloudSettings(UserInfo userInfo, CloudProvider cloudProvider) {
+	private CloudSettings cloudSettings(String user, CloudProvider cloudProvider) {
 		switch (cloudProvider) {
 			case AWS:
 				return AwsCloudSettings.builder()
-						.awsIamUser(userInfo.getName())
+						.awsIamUser(user)
 						.build();
 			case AZURE:
 				return AzureCloudSettings.builder()
-						.azureIamUser(userInfo.getName()).build();
+						.azureIamUser(user).build();
 			case GCP:
 				return GcpCloudSettings.builder()
-						.gcpIamUser(userInfo.getName()).build();
+						.gcpIamUser(user).build();
 			default:
 				throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
 		}
 	}
 
 	@SuppressWarnings("unchecked")
-	private <T extends ResourceBaseDTO<?>> T newResourceBaseDTO(UserInfo userInfo, CloudProvider cloudProvider,
+	private <T extends ResourceBaseDTO<?>> T newResourceBaseDTO(String user, CloudProvider cloudProvider,
 																Class<T> resourceClass) {
 		try {
 			return (T) resourceClass.newInstance()
-					.withEdgeUserName(getEdgeUserName(userInfo, cloudProvider))
-					.withCloudSettings(cloudSettings(userInfo, cloudProvider));
+					.withEdgeUserName(getEdgeUserName(user, cloudProvider))
+					.withCloudSettings(cloudSettings(user, cloudProvider));
 		} catch (Exception e) {
 			throw new DlabException("Cannot create instance of resource class " + resourceClass.getName() + ". " +
 					e.getLocalizedMessage(), e);
 		}
 	}
 
-	private String getEdgeUserName(UserInfo userInfo, CloudProvider cloudProvider) {
-		String edgeUser = UsernameUtils.replaceWhitespaces(userInfo.getSimpleName());
+	private String getEdgeUserName(String user, CloudProvider cloudProvider) {
+		String edgeUser = UsernameUtils.removeDomain(user);
 		switch (cloudProvider) {
 			case GCP:
 				return adjustUserName(configuration.getMaxUserNameLength(), edgeUser);
@@ -145,9 +145,9 @@ public class RequestBuilder {
 	}
 
 	@SuppressWarnings("unchecked")
-	private <T extends ResourceSysBaseDTO<?>> T newResourceSysBaseDTO(UserInfo userInfo, CloudProvider cloudProvider,
+	private <T extends ResourceSysBaseDTO<?>> T newResourceSysBaseDTO(String user, CloudProvider cloudProvider,
 																	  Class<T> resourceClass) {
-		return newResourceBaseDTO(userInfo, cloudProvider, resourceClass);
+		return newResourceBaseDTO(user, cloudProvider, resourceClass);
 	}
 
 	@SuppressWarnings("unchecked")
@@ -160,11 +160,11 @@ public class RequestBuilder {
 		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
 		switch (cloudProvider) {
 			case AWS:
-				exploratoryCreate = (T) newResourceSysBaseDTO(userInfo, cloudProvider, ExploratoryCreateAws.class)
+				exploratoryCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryCreateAws.class)
 						.withNotebookInstanceType(exploratory.getShape());
 				break;
 			case AZURE:
-				exploratoryCreate = (T) newResourceSysBaseDTO(userInfo, cloudProvider, ExploratoryCreateAzure.class)
+				exploratoryCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryCreateAzure.class)
 						.withNotebookInstanceSize(exploratory.getShape());
 				if (settingsDAO.isAzureDataLakeEnabled()) {
 					((ExploratoryCreateAzure) exploratoryCreate)
@@ -175,7 +175,7 @@ public class RequestBuilder {
 						.withAzureDataLakeEnabled(Boolean.toString(settingsDAO.isAzureDataLakeEnabled()));
 				break;
 			case GCP:
-				exploratoryCreate = (T) newResourceSysBaseDTO(userInfo, cloudProvider, ExploratoryCreateGcp.class)
+				exploratoryCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryCreateGcp.class)
 						.withNotebookInstanceType(exploratory.getShape());
 				break;
 			default:
@@ -204,7 +204,7 @@ public class RequestBuilder {
 		switch (cloudProvider) {
 			case AWS:
 			case GCP:
-				return (T) newResourceSysBaseDTO(userInfo, cloudProvider, ExploratoryGitCredsUpdateDTO.class)
+				return (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryGitCredsUpdateDTO.class)
 						.withNotebookInstanceName(userInstance.getExploratoryId())
 						.withGitCreds(exploratoryGitCredsDTO.getGitCreds())
 						.withNotebookImage(userInstance.getImageName())
@@ -213,7 +213,7 @@ public class RequestBuilder {
 						.withProject(userInstance.getProject())
 						.withEndpoint(userInstance.getEndpoint());
 			case AZURE:
-				T exploratoryStart = (T) newResourceSysBaseDTO(userInfo, cloudProvider, ExploratoryActionStartAzure.class)
+				T exploratoryStart = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryActionStartAzure.class)
 						.withNotebookInstanceName(userInstance.getExploratoryId())
 						.withGitCreds(exploratoryGitCredsDTO.getGitCreds())
 						.withNotebookImage(userInstance.getImageName())
@@ -237,7 +237,7 @@ public class RequestBuilder {
 	}
 
 	@SuppressWarnings("unchecked")
-	public <T extends ExploratoryActionDTO<T>> T newExploratoryStop(UserInfo userInfo, UserInstanceDTO userInstance, EndpointDTO endpointDTO) {
+	public <T extends ExploratoryActionDTO<T>> T newExploratoryStop(String user, UserInstanceDTO userInstance, EndpointDTO endpointDTO) {
 
 		T exploratoryStop;
 		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
@@ -245,10 +245,10 @@ public class RequestBuilder {
 		switch (cloudProvider) {
 			case AWS:
 			case GCP:
-				exploratoryStop = (T) newResourceSysBaseDTO(userInfo, cloudProvider, ExploratoryActionDTO.class);
+				exploratoryStop = (T) newResourceSysBaseDTO(user, cloudProvider, ExploratoryActionDTO.class);
 				break;
 			case AZURE:
-				exploratoryStop = (T) newResourceSysBaseDTO(userInfo, cloudProvider, ExploratoryActionStopAzure.class);
+				exploratoryStop = (T) newResourceSysBaseDTO(user, cloudProvider, ExploratoryActionStopAzure.class);
 				break;
 			default:
 				throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
@@ -268,7 +268,7 @@ public class RequestBuilder {
 																EndpointDTO endpointDTO,
 																ExploratoryGitCredsDTO exploratoryGitCredsDTO) {
 		checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
-		return newResourceSysBaseDTO(userInfo, endpointDTO.getCloudProvider(), ExploratoryGitCredsUpdateDTO.class)
+		return newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ExploratoryGitCredsUpdateDTO.class)
 				.withNotebookImage(instanceDTO.getImageName())
 				.withApplicationName(getApplicationNameFromImage(instanceDTO.getImageName()))
 				.withProject(instanceDTO.getProject())
@@ -281,7 +281,7 @@ public class RequestBuilder {
 	public LibraryInstallDTO newLibInstall(UserInfo userInfo, UserInstanceDTO userInstance,
 										   EndpointDTO endpointDTO, List<LibInstallDTO> libs) {
 		checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
-		return newResourceSysBaseDTO(userInfo, endpointDTO.getCloudProvider(), LibraryInstallDTO.class)
+		return newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), LibraryInstallDTO.class)
 				.withNotebookImage(userInstance.getImageName())
 				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
 				.withNotebookInstanceName(userInstance.getExploratoryId())
@@ -296,7 +296,7 @@ public class RequestBuilder {
 																	   UserInstanceDTO userInstance,
 																	   EndpointDTO endpointDTO) {
 		checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
-		return (T) newResourceSysBaseDTO(userInfo, endpointDTO.getCloudProvider(), ExploratoryActionDTO.class)
+		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ExploratoryActionDTO.class)
 				.withNotebookInstanceName(userInstance.getExploratoryId())
 				.withProject(userInstance.getProject())
 				.withEndpoint(endpointDTO.getName())
@@ -310,7 +310,7 @@ public class RequestBuilder {
 														 UserComputationalResource computationalResource,
 														 List<LibInstallDTO> libs, EndpointDTO endpointDTO) {
 		checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
-		return (T) newResourceSysBaseDTO(userInfo, endpointDTO.getCloudProvider(), LibraryInstallDTO.class)
+		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), LibraryInstallDTO.class)
 				.withComputationalId(computationalResource.getComputationalId())
 				.withComputationalName(computationalResource.getComputationalName())
 				.withExploratoryName(userInstance.getExploratoryName())
@@ -329,7 +329,7 @@ public class RequestBuilder {
 																		 EndpointDTO endpointDTO) {
 
 		checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
-		return (T) newResourceSysBaseDTO(userInfo, endpointDTO.getCloudProvider(), LibListComputationalDTO.class)
+		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), LibListComputationalDTO.class)
 				.withComputationalId(computationalResource.getComputationalId())
 				.withProject(userInstance.getProject())
 				.withEndpoint(endpointDTO.getName())
@@ -350,7 +350,7 @@ public class RequestBuilder {
 				throw new UnsupportedOperationException("Creating dataengine service is not supported yet");
 			case AWS:
 				AwsComputationalCreateForm awsForm = (AwsComputationalCreateForm) form;
-				computationalCreate = (T) newResourceSysBaseDTO(userInfo, cloudProvider, ComputationalCreateAws.class)
+				computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ComputationalCreateAws.class)
 						.withInstanceCount(awsForm.getInstanceCount())
 						.withMasterInstanceType(awsForm.getMasterInstanceType())
 						.withSlaveInstanceType(awsForm.getSlaveInstanceType())
@@ -362,7 +362,7 @@ public class RequestBuilder {
 				break;
 			case GCP:
 				GcpComputationalCreateForm gcpForm = (GcpComputationalCreateForm) form;
-				computationalCreate = (T) newResourceSysBaseDTO(userInfo, cloudProvider, ComputationalCreateGcp.class)
+				computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ComputationalCreateGcp.class)
 						.withMasterInstanceCount(gcpForm.getMasterInstanceCount())
 						.withSlaveInstanceCount(gcpForm.getSlaveInstanceCount())
 						.withPreemptibleCount(gcpForm.getPreemptibleCount())
@@ -397,7 +397,7 @@ public class RequestBuilder {
 		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
 		switch (cloudProvider) {
 			case AWS:
-				computationalCreate = (T) newResourceSysBaseDTO(userInfo, cloudProvider, SparkComputationalCreateAws.class)
+				computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, SparkComputationalCreateAws.class)
 						.withDataEngineInstanceCount(form.getDataEngineInstanceCount())
 						.withDataEngineMasterShape(form.getDataEngineInstanceShape())
 						.withDataEngineSlaveShape(form.getDataEngineInstanceShape())
@@ -405,7 +405,7 @@ public class RequestBuilder {
 						.withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
 				break;
 			case AZURE:
-				computationalCreate = (T) newResourceSysBaseDTO(userInfo, cloudProvider, SparkComputationalCreateAzure.class)
+				computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, SparkComputationalCreateAzure.class)
 						.withDataEngineInstanceCount(form.getDataEngineInstanceCount())
 						.withDataEngineMasterSize(form.getDataEngineInstanceShape())
 						.withDataEngineSlaveSize(form.getDataEngineInstanceShape())
@@ -421,7 +421,7 @@ public class RequestBuilder {
 
 				break;
 			case GCP:
-				computationalCreate = (T) newResourceSysBaseDTO(userInfo, cloudProvider, SparkComputationalCreateGcp.class)
+				computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, SparkComputationalCreateGcp.class)
 						.withDataEngineInstanceCount(form.getDataEngineInstanceCount())
 						.withDataEngineMasterSize(form.getDataEngineInstanceShape())
 						.withDataEngineSlaveSize(form.getDataEngineInstanceShape())
@@ -452,7 +452,7 @@ public class RequestBuilder {
 		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
 		switch (cloudProvider) {
 			case AWS:
-				AwsComputationalTerminateDTO terminateDTO = newResourceSysBaseDTO(userInfo, cloudProvider,
+				AwsComputationalTerminateDTO terminateDTO = newResourceSysBaseDTO(userInfo.getName(), cloudProvider,
 						AwsComputationalTerminateDTO.class);
 				if (computationalResource.getDataEngineType() == DataEngineType.CLOUD_SERVICE) {
 					terminateDTO.setClusterName(computationalResource.getComputationalId());
@@ -460,10 +460,10 @@ public class RequestBuilder {
 				computationalTerminate = (T) terminateDTO;
 				break;
 			case AZURE:
-				computationalTerminate = (T) newResourceSysBaseDTO(userInfo, cloudProvider, ComputationalTerminateDTO.class);
+				computationalTerminate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ComputationalTerminateDTO.class);
 				break;
 			case GCP:
-				GcpComputationalTerminateDTO gcpTerminateDTO = newResourceSysBaseDTO(userInfo, cloudProvider,
+				GcpComputationalTerminateDTO gcpTerminateDTO = newResourceSysBaseDTO(userInfo.getName(), cloudProvider,
 						GcpComputationalTerminateDTO.class);
 				if (computationalResource.getDataEngineType() == DataEngineType.CLOUD_SERVICE) {
 					gcpTerminateDTO.setClusterName(computationalResource.getComputationalId());
@@ -486,7 +486,7 @@ public class RequestBuilder {
 	@SuppressWarnings("unchecked")
 	public <T extends ComputationalBase<T>> T newComputationalStop(UserInfo userInfo, UserInstanceDTO exploratory,
 																   String computationalName, EndpointDTO endpointDTO) {
-		return (T) newResourceSysBaseDTO(userInfo, endpointDTO.getCloudProvider(), ComputationalStopDTO.class)
+		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ComputationalStopDTO.class)
 				.withExploratoryName(exploratory.getExploratoryName())
 				.withComputationalName(computationalName)
 				.withNotebookInstanceName(exploratory.getExploratoryId())
@@ -498,7 +498,7 @@ public class RequestBuilder {
 	@SuppressWarnings("unchecked")
 	public <T extends ComputationalBase<T>> T newComputationalStart(UserInfo userInfo, UserInstanceDTO exploratory,
 																	String computationalName, EndpointDTO endpointDTO) {
-		return (T) newResourceSysBaseDTO(userInfo, endpointDTO.getCloudProvider(), ComputationalStartDTO.class)
+		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ComputationalStartDTO.class)
 				.withExploratoryName(exploratory.getExploratoryName())
 				.withComputationalName(computationalName)
 				.withNotebookInstanceName(exploratory.getExploratoryId())
@@ -511,7 +511,7 @@ public class RequestBuilder {
 	public <T extends ExploratoryImageDTO> T newExploratoryImageCreate(UserInfo userInfo, UserInstanceDTO userInstance,
 																	   String imageName, EndpointDTO endpointDTO, ProjectDTO projectDTO) {
 		checkInappropriateCloudProviderOrElseThrowException(endpointDTO.getCloudProvider());
-		return (T) newResourceSysBaseDTO(userInfo, endpointDTO.getCloudProvider(), ExploratoryImageDTO.class)
+		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ExploratoryImageDTO.class)
 				.withProject(userInstance.getProject())
 				.withNotebookInstanceName(userInstance.getExploratoryId())
 				.withExploratoryName(userInstance.getExploratoryName())
@@ -527,7 +527,7 @@ public class RequestBuilder {
 	public <T extends ComputationalBase<T>> T newComputationalCheckInactivity(UserInfo userInfo,
 																			  UserInstanceDTO exploratory,
 																			  UserComputationalResource cr, EndpointDTO endpointDTO) {
-		return (T) newResourceSysBaseDTO(userInfo, endpointDTO.getCloudProvider(), ComputationalCheckInactivityDTO.class)
+		return (T) newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(), ComputationalCheckInactivityDTO.class)
 				.withExploratoryName(exploratory.getExploratoryName())
 				.withComputationalName(cr.getComputationalName())
 				.withNotebookInstanceName(exploratory.getExploratoryId())
@@ -558,7 +558,7 @@ public class RequestBuilder {
 																UserComputationalResource compRes,
 																List<ClusterConfig> config, EndpointDTO endpointDTO) {
 		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
-		final ComputationalClusterConfigDTO clusterConfigDTO = newResourceSysBaseDTO(userInfo, cloudProvider,
+		final ComputationalClusterConfigDTO clusterConfigDTO = newResourceSysBaseDTO(userInfo.getName(), cloudProvider,
 				ComputationalClusterConfigDTO.class)
 				.withExploratoryName(userInstanceDTO.getExploratoryName())
 				.withNotebookInstanceName(userInstanceDTO.getExploratoryId())
@@ -582,7 +582,7 @@ public class RequestBuilder {
 
 		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
 		final ExploratoryReconfigureSparkClusterActionDTO dto =
-				newResourceSysBaseDTO(userInfo, cloudProvider, ExploratoryReconfigureSparkClusterActionDTO.class)
+				newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ExploratoryReconfigureSparkClusterActionDTO.class)
 						.withNotebookInstanceName(userInstance.getExploratoryId())
 						.withExploratoryName(userInstance.getExploratoryName())
 						.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
@@ -600,7 +600,7 @@ public class RequestBuilder {
 	public ExploratoryCheckInactivityAction newExploratoryCheckInactivityAction(UserInfo userInfo,
 																				UserInstanceDTO userInstance,
 																				EndpointDTO endpointDTO) {
-		final ExploratoryCheckInactivityAction dto = newResourceSysBaseDTO(userInfo, endpointDTO.getCloudProvider(),
+		final ExploratoryCheckInactivityAction dto = newResourceSysBaseDTO(userInfo.getName(), endpointDTO.getCloudProvider(),
 				ExploratoryCheckInactivityAction.class);
 		dto.withNotebookInstanceName(userInstance.getExploratoryId())
 				.withNotebookImage(userInstance.getImageName())
@@ -618,12 +618,12 @@ public class RequestBuilder {
 				.tag(projectDTO.getTag())
 				.endpoint(endpointDTO.getName())
 				.build()
-				.withCloudSettings(cloudSettings(userInfo, endpointDTO.getCloudProvider()));
+				.withCloudSettings(cloudSettings(userInfo.getName(), endpointDTO.getCloudProvider()));
 	}
 
 	public ProjectActionDTO newProjectAction(UserInfo userInfo, String project, EndpointDTO endpointDTO) {
 		return new ProjectActionDTO(project, endpointDTO.getName())
-				.withCloudSettings(cloudSettings(userInfo, endpointDTO.getCloudProvider()));
+				.withCloudSettings(cloudSettings(userInfo.getName(), endpointDTO.getCloudProvider()));
 	}
 
 	/**
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ExploratoryResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ExploratoryResourceTest.java
index bccfa8b..a3e1dbd 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ExploratoryResourceTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ExploratoryResourceTest.java
@@ -46,6 +46,7 @@ import java.util.List;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyList;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.eq;
@@ -70,98 +71,97 @@ public class ExploratoryResourceTest extends TestBase {
 
 	@Test
 	public void create() {
-		when(exploratoryService.create(any(UserInfo.class), any(Exploratory.class), anyString())).thenReturn(
-				"someUuid");
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.put(Entity.json(getExploratoryCreateFormDTO()));
-
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals("someUuid", response.readEntity(String.class));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verify(exploratoryService).create(refEq(getUserInfo()), refEq(getExploratory(getExploratoryCreateFormDTO())),
-				eq("project"));
-		verifyNoMoreInteractions(exploratoryService);
+        when(exploratoryService.create(any(UserInfo.class), any(Exploratory.class), anyString(), anyString())).thenReturn(
+                "someUuid");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .put(Entity.json(getExploratoryCreateFormDTO()));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals("someUuid", response.readEntity(String.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(exploratoryService).create(refEq(getUserInfo()), refEq(getExploratory(getExploratoryCreateFormDTO())),
+                eq("project"), eq("someName"));
+        verifyNoMoreInteractions(exploratoryService);
 	}
 
 	@Test
 	public void createWithException() {
-		doThrow(new DlabException("Could not create exploratory environment"))
-				.when(exploratoryService).create(any(UserInfo.class), any(Exploratory.class), anyString());
+        doThrow(new DlabException("Could not create exploratory environment"))
+                .when(exploratoryService).create(any(UserInfo.class), any(Exploratory.class), anyString(), anyString());
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure_provision/exploratory_environment")
 				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.put(Entity.json(getExploratoryCreateFormDTO()));
+                .header("Authorization", "Bearer " + TOKEN)
+                .put(Entity.json(getExploratoryCreateFormDTO()));
 
-		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
-		String expectedJson = "\"code\":500,\"message\":\"There was an error processing your request. " +
-				"It has been logged";
-		String actualJson = response.readEntity(String.class);
-		assertTrue(actualJson.contains(expectedJson));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+        assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
+        String expectedJson = "\"code\":500,\"message\":\"There was an error processing your request. " +
+                "It has been logged";
+        String actualJson = response.readEntity(String.class);
+        assertTrue(actualJson.contains(expectedJson));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(exploratoryService).create(getUserInfo(), getExploratory(getExploratoryCreateFormDTO()), "project");
-		verifyNoMoreInteractions(exploratoryService);
-	}
+        verify(exploratoryService).create(getUserInfo(), getExploratory(getExploratoryCreateFormDTO()), "project", "someName");
+        verifyNoMoreInteractions(exploratoryService);
+    }
 
 	@Test
 	public void start() {
-		ExploratoryActionFormDTO exploratoryDTO = getExploratoryActionFormDTO();
-		when(exploratoryService.start(any(UserInfo.class), anyString(), anyString())).thenReturn("someUuid");
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json(exploratoryDTO));
+        ExploratoryActionFormDTO exploratoryDTO = getExploratoryActionFormDTO();
+        when(exploratoryService.start(any(UserInfo.class), anyString(), anyString(), anyList())).thenReturn("someUuid");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(exploratoryDTO));
 
-		assertEquals(HttpStatus.SC_OK, response.getStatus());
-		assertEquals("someUuid", response.readEntity(String.class));
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals("someUuid", response.readEntity(String.class));
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(exploratoryService).start(getUserInfo(), exploratoryDTO.getNotebookInstanceName(),
-				exploratoryDTO.getProjectName());
+        verify(exploratoryService).start(getUserInfo(), exploratoryDTO.getNotebookInstanceName(), exploratoryDTO.getProjectName(), null);
 
-		verifyZeroInteractions(exploratoryService);
-	}
+        verifyZeroInteractions(exploratoryService);
+    }
 
 	@Test
 	public void startUnprocessableEntity() {
-		when(exploratoryService.start(any(UserInfo.class), anyString(), anyString())).thenReturn("someUuid");
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json(getEmptyExploratoryActionFormDTO()));
+        when(exploratoryService.start(any(UserInfo.class), anyString(), anyString(), anyList())).thenReturn("someUuid");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getEmptyExploratoryActionFormDTO()));
 
-		assertEquals(HttpStatus.SC_UNPROCESSABLE_ENTITY, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+        assertEquals(HttpStatus.SC_UNPROCESSABLE_ENTITY, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verifyZeroInteractions(exploratoryService);
+        verifyZeroInteractions(exploratoryService);
 	}
 
 	@Test
 	public void startWithFailedAuth() throws AuthenticationException {
-		authFailSetup();
-		when(exploratoryService.start(any(UserInfo.class), anyString(), anyString())).thenReturn("someUuid");
-		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_provision/exploratory_environment")
-				.request()
-				.header("Authorization", "Bearer " + TOKEN)
-				.post(Entity.json(getEmptyExploratoryActionFormDTO()));
-
-		assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
-		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-		verifyZeroInteractions(exploratoryService);
+        authFailSetup();
+        when(exploratoryService.start(any(UserInfo.class), anyString(), anyString(), anyList())).thenReturn("someUuid");
+        final Response response = resources.getJerseyTest()
+                .target("/infrastructure_provision/exploratory_environment")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getEmptyExploratoryActionFormDTO()));
+
+        assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatus());
+        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verifyZeroInteractions(exploratoryService);
 	}
 
 	@Test
 	public void stop() {
-		when(exploratoryService.stop(any(UserInfo.class), anyString(), anyString())).thenReturn("someUuid");
+		when(exploratoryService.stop(any(UserInfo.class), anyString(), anyString(), anyString(), anyList())).thenReturn("someUuid");
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure_provision/exploratory_environment/project/someName/stop")
 				.request()
@@ -172,14 +172,14 @@ public class ExploratoryResourceTest extends TestBase {
 		assertEquals("someUuid", response.readEntity(String.class));
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(exploratoryService).stop(getUserInfo(), "project", "someName");
+		verify(exploratoryService).stop(getUserInfo(), getUserInfo().getName(), "project", "someName", null);
 		verifyNoMoreInteractions(exploratoryService);
 	}
 
 	@Test
 	public void stopWithFailedAuth() throws AuthenticationException {
 		authFailSetup();
-		when(exploratoryService.stop(any(UserInfo.class), anyString(), anyString())).thenReturn("someUuid");
+		when(exploratoryService.stop(any(UserInfo.class), anyString(), anyString(), anyString(), anyList())).thenReturn("someUuid");
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure_provision/exploratory_environment/project/someName/stop")
 				.request()
@@ -190,14 +190,14 @@ public class ExploratoryResourceTest extends TestBase {
 		assertEquals("someUuid", response.readEntity(String.class));
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(exploratoryService).stop(getUserInfo(), "project", "someName");
+		verify(exploratoryService).stop(getUserInfo(), getUserInfo().getName(), "project", "someName", null);
 		verifyNoMoreInteractions(exploratoryService);
 	}
 
 	@Test
 	public void stopWithException() {
 		doThrow(new DlabException("Could not stop exploratory environment"))
-				.when(exploratoryService).stop(any(UserInfo.class), anyString(), anyString());
+				.when(exploratoryService).stop(any(UserInfo.class), anyString(), anyString(), anyString(), anyList());
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure_provision/exploratory_environment/project/someName/stop")
 				.request()
@@ -211,13 +211,13 @@ public class ExploratoryResourceTest extends TestBase {
 		assertTrue(actualJson.contains(expectedJson));
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(exploratoryService).stop(getUserInfo(), "project", "someName");
+		verify(exploratoryService).stop(getUserInfo(), getUserInfo().getName(), "project", "someName", null);
 		verifyNoMoreInteractions(exploratoryService);
 	}
 
 	@Test
 	public void terminate() {
-		when(exploratoryService.terminate(any(UserInfo.class), anyString(), anyString())).thenReturn("someUuid");
+		when(exploratoryService.terminate(any(UserInfo.class), anyString(), anyString(), anyString(), anyList())).thenReturn("someUuid");
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure_provision/exploratory_environment/project/someName/terminate")
 				.request()
@@ -228,14 +228,14 @@ public class ExploratoryResourceTest extends TestBase {
 		assertEquals("someUuid", response.readEntity(String.class));
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(exploratoryService).terminate(getUserInfo(), "project", "someName");
+		verify(exploratoryService).terminate(getUserInfo(), getUserInfo().getName(), "project", "someName", null);
 		verifyNoMoreInteractions(exploratoryService);
 	}
 
 	@Test
 	public void terminateWithFailedAuth() throws AuthenticationException {
 		authFailSetup();
-		when(exploratoryService.terminate(any(UserInfo.class), anyString(), anyString())).thenReturn("someUuid");
+		when(exploratoryService.terminate(any(UserInfo.class), anyString(), anyString(), anyString(), anyList())).thenReturn("someUuid");
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure_provision/exploratory_environment/project/someName/terminate")
 				.request()
@@ -246,14 +246,14 @@ public class ExploratoryResourceTest extends TestBase {
 		assertEquals("someUuid", response.readEntity(String.class));
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(exploratoryService).terminate(getUserInfo(), "project", "someName");
+		verify(exploratoryService).terminate(getUserInfo(), getUserInfo().getName(), "project", "someName", null);
 		verifyNoMoreInteractions(exploratoryService);
 	}
 
 	@Test
 	public void terminateWithException() {
 		doThrow(new DlabException("Could not terminate exploratory environment"))
-				.when(exploratoryService).terminate(any(UserInfo.class), anyString(), anyString());
+				.when(exploratoryService).terminate(any(UserInfo.class), anyString(), anyString(), anyString(), anyList());
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure_provision/exploratory_environment/project/someName/terminate")
 				.request()
@@ -267,7 +267,7 @@ public class ExploratoryResourceTest extends TestBase {
 		assertTrue(actualJson.contains(expectedJson));
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(exploratoryService).terminate(getUserInfo(), "project", "someName");
+		verify(exploratoryService).terminate(getUserInfo(), getUserInfo().getName(), "project", "someName", null);
 		verifyNoMoreInteractions(exploratoryService);
 	}
 
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImplTest.java
index 460c2f9..7bde7a6 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImplTest.java
@@ -48,6 +48,7 @@ import java.util.List;
 import java.util.Optional;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyList;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anySet;
 import static org.mockito.Mockito.anyString;
@@ -63,7 +64,8 @@ import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
 public class EnvironmentServiceImplTest {
-
+	private static final String AUDIT_QUOTA_MESSAGE = "Billing quota reached";
+	private static final String DLAB_SYSTEM_USER = "DLab system user";
 	private static final String USER = "test";
 	private static final String EXPLORATORY_NAME_1 = "expName1";
 	private static final String EXPLORATORY_NAME_2 = "expName2";
@@ -129,33 +131,33 @@ public class EnvironmentServiceImplTest {
 		final ProjectDTO projectDTO = getProjectDTO();
 		when(exploratoryDAO.fetchRunningExploratoryFieldsForProject(anyString())).thenReturn(getUserInstances());
 		when(securityService.getServiceAccountInfo(anyString())).thenReturn(userInfo);
-		when(exploratoryService.stop(any(UserInfo.class), anyString(), anyString())).thenReturn(UUID);
+		when(exploratoryService.stop(any(UserInfo.class), anyString(), anyString(), anyString(), anyList())).thenReturn(UUID);
 		when(projectService.get(anyString())).thenReturn(projectDTO);
 		doNothing().when(projectService).stop(any(UserInfo.class), anyString(), anyString());
 
 		environmentService.stopProjectEnvironment(PROJECT_NAME);
 
 		verify(exploratoryDAO).fetchRunningExploratoryFieldsForProject(PROJECT_NAME);
-		verify(exploratoryService).stop(refEq(userInfo), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1));
-		verify(exploratoryService).stop(refEq(userInfo), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_2));
-		verify(securityService, times(2)).getServiceAccountInfo(USER);
+		verify(exploratoryService).stop(refEq(userInfo), eq(USER), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq(Collections.singletonList(AUDIT_QUOTA_MESSAGE)));
+		verify(exploratoryService).stop(refEq(userInfo), eq(USER), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_2), eq(Collections.singletonList(AUDIT_QUOTA_MESSAGE)));
+		verify(securityService, times(2)).getServiceAccountInfo(DLAB_SYSTEM_USER);
 		verify(securityService).getServiceAccountInfo(ADMIN);
 		verify(projectService).get(eq(PROJECT_NAME));
 		verify(projectService).stop(refEq(userInfo), eq(ENDPOINT_NAME), eq(PROJECT_NAME));
 		verify(exploratoryDAO).fetchProjectExploratoriesWhereStatusIn(PROJECT_NAME, Arrays.asList(UserInstanceStatus.CREATING,
 				UserInstanceStatus.STARTING, UserInstanceStatus.CREATING_IMAGE),
 				UserInstanceStatus.CREATING, UserInstanceStatus.STARTING, UserInstanceStatus.CREATING_IMAGE);
-		verifyNoMoreInteractions(exploratoryDAO, exploratoryService, securityService, projectService);
+		verifyNoMoreInteractions(exploratoryDAO, exploratoryService, projectService);
 	}
 
 	@Test
 	public void stopExploratory() {
 		final UserInfo userInfo = getUserInfo();
-		when(exploratoryService.stop(any(UserInfo.class), anyString(), anyString())).thenReturn(UUID);
+		when(exploratoryService.stop(any(UserInfo.class), anyString(), anyString(), anyString(), anyList())).thenReturn(UUID);
 
-		environmentService.stopExploratory(new UserInfo(USER, TOKEN), USER, PROJECT_NAME, EXPLORATORY_NAME_1);
+		environmentService.stopExploratory(userInfo, USER, PROJECT_NAME, EXPLORATORY_NAME_1);
 
-		verify(exploratoryService).stop(refEq(userInfo), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1));
+		verify(exploratoryService).stop(refEq(userInfo), eq(USER), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq(null));
 		verifyNoMoreInteractions(securityService, exploratoryService);
 	}
 
@@ -173,11 +175,11 @@ public class EnvironmentServiceImplTest {
 	@Test
 	public void terminateExploratory() {
 		final UserInfo userInfo = getUserInfo();
-		when(exploratoryService.terminate(any(UserInfo.class), anyString(), anyString())).thenReturn(UUID);
+		when(exploratoryService.terminate(any(UserInfo.class), anyString(), anyString(), anyString(), anyList())).thenReturn(UUID);
 
 		environmentService.terminateExploratory(userInfo, USER, PROJECT_NAME, EXPLORATORY_NAME_1);
 
-		verify(exploratoryService).terminate(refEq(userInfo), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1));
+		verify(exploratoryService).terminate(refEq(userInfo), eq(USER), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq(null));
 		verifyNoMoreInteractions(securityService, exploratoryService);
 	}
 
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImplTest.java
index 5d21167..eee6d0c 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImplTest.java
@@ -146,7 +146,7 @@ public class ExploratoryServiceImplTest {
                 .thenReturn(UUID);
         when(requestId.put(anyString(), anyString())).thenReturn(UUID);
 
-        String uuid = exploratoryService.start(userInfo, EXPLORATORY_NAME, "project");
+        String uuid = exploratoryService.start(userInfo, EXPLORATORY_NAME, "project", null);
         assertNotNull(uuid);
         assertEquals(UUID, uuid);
 
@@ -165,7 +165,7 @@ public class ExploratoryServiceImplTest {
         doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
                 .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
         try {
-            exploratoryService.start(userInfo, EXPLORATORY_NAME, PROJECT);
+            exploratoryService.start(userInfo, EXPLORATORY_NAME, PROJECT, null);
         } catch (DlabException e) {
             assertEquals("Could not start exploratory environment expName: Exploratory for user with " +
                     "name not found", e.getMessage());
@@ -188,7 +188,7 @@ public class ExploratoryServiceImplTest {
 
         ExploratoryActionDTO eaDto = new ExploratoryActionDTO();
         eaDto.withExploratoryName(EXPLORATORY_NAME);
-        when(requestBuilder.newExploratoryStop(any(UserInfo.class), any(UserInstanceDTO.class), any(EndpointDTO.class)))
+        when(requestBuilder.newExploratoryStop(anyString(), any(UserInstanceDTO.class), any(EndpointDTO.class)))
                 .thenReturn(eaDto);
 
         String exploratoryStop = "exploratory/stop";
@@ -196,7 +196,7 @@ public class ExploratoryServiceImplTest {
                 (UUID);
         when(requestId.put(anyString(), anyString())).thenReturn(UUID);
 
-        String uuid = exploratoryService.stop(userInfo, PROJECT, EXPLORATORY_NAME);
+        String uuid = exploratoryService.stop(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, null);
         assertNotNull(uuid);
         assertEquals(UUID, uuid);
 
@@ -218,7 +218,7 @@ public class ExploratoryServiceImplTest {
         doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
                 .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
         try {
-            exploratoryService.stop(userInfo, PROJECT, EXPLORATORY_NAME);
+            exploratoryService.stop(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, null);
         } catch (DlabException e) {
             assertEquals("Could not stop exploratory environment expName: Exploratory for user with " +
                     "name not found", e.getMessage());
@@ -241,7 +241,7 @@ public class ExploratoryServiceImplTest {
 
         ExploratoryActionDTO eaDto = new ExploratoryActionDTO();
         eaDto.withExploratoryName(EXPLORATORY_NAME);
-        when(requestBuilder.newExploratoryStop(any(UserInfo.class), any(UserInstanceDTO.class), any(EndpointDTO.class)))
+        when(requestBuilder.newExploratoryStop(anyString(), any(UserInstanceDTO.class), any(EndpointDTO.class)))
                 .thenReturn(eaDto);
 
         String exploratoryTerminate = "exploratory/terminate";
@@ -249,7 +249,7 @@ public class ExploratoryServiceImplTest {
                 (UUID);
         when(requestId.put(anyString(), anyString())).thenReturn(UUID);
 
-        String uuid = exploratoryService.terminate(userInfo, PROJECT, EXPLORATORY_NAME);
+        String uuid = exploratoryService.terminate(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, null);
         assertNotNull(uuid);
         assertEquals(UUID, uuid);
 
@@ -260,7 +260,7 @@ public class ExploratoryServiceImplTest {
         verify(computationalDAO).updateComputationalStatusesForExploratory(USER, PROJECT, EXPLORATORY_NAME,
                 UserInstanceStatus.TERMINATING, UserInstanceStatus.TERMINATING, UserInstanceStatus.TERMINATED,
                 UserInstanceStatus.FAILED);
-        verify(requestBuilder).newExploratoryStop(userInfo, userInstance, endpointDTO());
+        verify(requestBuilder).newExploratoryStop(userInfo.getName(), userInstance, endpointDTO());
         verify(provisioningService).post(endpointDTO().getUrl() + exploratoryTerminate, TOKEN, eaDto, String.class);
         verify(requestId).put(USER, UUID);
         verifyNoMoreInteractions(exploratoryDAO, computationalDAO, requestBuilder, provisioningService, requestId);
@@ -272,7 +272,7 @@ public class ExploratoryServiceImplTest {
         doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
                 .when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString(), anyString());
         try {
-            exploratoryService.terminate(userInfo, PROJECT, EXPLORATORY_NAME);
+            exploratoryService.terminate(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, null);
         } catch (DlabException e) {
             assertEquals("Could not terminate exploratory environment expName: Exploratory for user " +
                     "with name not found", e.getMessage());
@@ -295,43 +295,43 @@ public class ExploratoryServiceImplTest {
 		ExploratoryGitCredsDTO egcDto = new ExploratoryGitCredsDTO();
 		when(gitCredsDAO.findGitCreds(anyString())).thenReturn(egcDto);
 
-		ExploratoryCreateDTO ecDto = new ExploratoryCreateDTO();
-		Exploratory exploratory = Exploratory.builder().name(EXPLORATORY_NAME).endpoint("test").build();
-		when(requestBuilder.newExploratoryCreate(any(ProjectDTO.class), any(EndpointDTO.class),
-				any(Exploratory.class), any(UserInfo.class), any(ExploratoryGitCredsDTO.class), anyMapOf(String.class, String.class))).thenReturn(ecDto);
-		String exploratoryCreate = "exploratory/create";
-		when(provisioningService.post(anyString(), anyString(), any(ExploratoryCreateDTO.class), any()))
-				.thenReturn(UUID);
-		when(requestId.put(anyString(), anyString())).thenReturn(UUID);
+        ExploratoryCreateDTO ecDto = new ExploratoryCreateDTO();
+        Exploratory exploratory = Exploratory.builder().name(EXPLORATORY_NAME).endpoint("test").build();
+        when(requestBuilder.newExploratoryCreate(any(ProjectDTO.class), any(EndpointDTO.class),
+                any(Exploratory.class), any(UserInfo.class), any(ExploratoryGitCredsDTO.class), anyMapOf(String.class, String.class))).thenReturn(ecDto);
+        String exploratoryCreate = "exploratory/create";
+        when(provisioningService.post(anyString(), anyString(), any(ExploratoryCreateDTO.class), any()))
+                .thenReturn(UUID);
+        when(requestId.put(anyString(), anyString())).thenReturn(UUID);
 
-		String uuid = exploratoryService.create(userInfo, exploratory, "project");
-		assertNotNull(uuid);
-		assertEquals(UUID, uuid);
+        String uuid = exploratoryService.create(userInfo, exploratory, "project", "exploratory");
+        assertNotNull(uuid);
+        assertEquals(UUID, uuid);
 
-		userInstance.withStatus("creating");
-		userInstance.withResources(Collections.emptyList());
-		verify(projectService).get("project");
-		verify(exploratoryDAO).insertExploratory(userInstance);
-		verify(gitCredsDAO).findGitCreds(USER);
-		verify(requestBuilder).newExploratoryCreate(projectDTO, endpointDTO(), exploratory, userInfo, egcDto, Collections.emptyMap());
-		verify(provisioningService).post(endpointDTO().getUrl() + exploratoryCreate, TOKEN, ecDto, String.class);
+        userInstance.withStatus("creating");
+        userInstance.withResources(Collections.emptyList());
+        verify(projectService).get("project");
+        verify(exploratoryDAO).insertExploratory(userInstance);
+        verify(gitCredsDAO).findGitCreds(USER);
+        verify(requestBuilder).newExploratoryCreate(projectDTO, endpointDTO(), exploratory, userInfo, egcDto, Collections.emptyMap());
+        verify(provisioningService).post(endpointDTO().getUrl() + exploratoryCreate, TOKEN, ecDto, String.class);
 		verify(requestId).put(USER, UUID);
 		verifyNoMoreInteractions(projectService, exploratoryDAO, gitCredsDAO, requestBuilder, provisioningService, requestId);
 	}
 
 	@Test
 	public void createWhenMethodInsertExploratoryThrowsException() {
-		when(endpointService.get(anyString())).thenReturn(endpointDTO());
-		doThrow(new RuntimeException("Exploratory for user with name not found"))
-				.when(exploratoryDAO).insertExploratory(any(UserInstanceDTO.class));
-		expectedException.expect(DlabException.class);
-		expectedException.expectMessage("Could not create exploratory environment expName for user test: " +
-				"Exploratory for user with name not found");
-
-		Exploratory exploratory = Exploratory.builder().name(EXPLORATORY_NAME).build();
-		exploratoryService.create(userInfo, exploratory, "project");
-		verify(endpointService).get(anyString());
-	}
+        when(endpointService.get(anyString())).thenReturn(endpointDTO());
+        doThrow(new RuntimeException("Exploratory for user with name not found"))
+                .when(exploratoryDAO).insertExploratory(any(UserInstanceDTO.class));
+        expectedException.expect(DlabException.class);
+        expectedException.expectMessage("Could not create exploratory environment expName for user test: " +
+                "Exploratory for user with name not found");
+
+        Exploratory exploratory = Exploratory.builder().name(EXPLORATORY_NAME).build();
+        exploratoryService.create(userInfo, exploratory, "project", "exploratory");
+        verify(endpointService).get(anyString());
+    }
 
 	@Test
 	public void createWhenMethodInsertExploratoryThrowsExceptionWithItsCatching() {
@@ -339,8 +339,8 @@ public class ExploratoryServiceImplTest {
 		doThrow(new RuntimeException()).when(exploratoryDAO).insertExploratory(any(UserInstanceDTO.class));
 		Exploratory exploratory = Exploratory.builder().name(EXPLORATORY_NAME).endpoint("test").build();
 		try {
-			exploratoryService.create(userInfo, exploratory, "project");
-		} catch (DlabException e) {
+            exploratoryService.create(userInfo, exploratory, "project", "exploratory");
+        } catch (DlabException e) {
 			assertEquals("Could not create exploratory environment expName for user test: null",
 					e.getMessage());
 		}
@@ -369,8 +369,8 @@ public class ExploratoryServiceImplTest {
 
 		when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
 		try {
-			exploratoryService.create(userInfo, exploratory, "project");
-		} catch (DlabException e) {
+            exploratoryService.create(userInfo, exploratory, "project", "exploratory");
+        } catch (DlabException e) {
 			assertEquals("Could not create exploratory environment expName for user test: Cannot create instance " +
 					"of resource class ", e.getMessage());
 		}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImplTest.java
index c025651..2b535fe 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImplTest.java
@@ -80,11 +80,12 @@ import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
 public class SchedulerJobServiceImplTest {
-
+	private static final String AUDIT_MESSAGE = "Scheduled action";
 	private final String USER = "test";
 	private final String EXPLORATORY_NAME = "explName";
 	private final String COMPUTATIONAL_NAME = "compName";
 	private final String PROJECT = "project";
+	private static final String DLAB_SYSTEM_USER = "DLab system user";
 	private SchedulerJobDTO schedulerJobDTO;
 	private UserInstanceDTO userInstance;
 
@@ -603,20 +604,21 @@ public class SchedulerJobServiceImplTest {
 
 	@Test
 	public void testStopExploratoryByScheduler() {
+		UserInfo userInfo = getUserInfo();
 		when(schedulerJobDAO.getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(any(UserInstanceStatus.class), any(Date.class))).
 				thenReturn(singletonList(getSchedulerJobData(LocalDate.now(), LocalDate.now().plusDays(1),
 						Arrays.asList(DayOfWeek.values()), Arrays.asList(DayOfWeek.values()),
 						LocalDateTime.of(LocalDate.now(),
 								LocalTime.now().truncatedTo(ChronoUnit.MINUTES)), false, USER,
 						LocalTime.now().truncatedTo(ChronoUnit.MINUTES))));
-		when(securityService.getServiceAccountInfo(anyString())).thenReturn(getUserInfo());
+		when(securityService.getServiceAccountInfo(anyString())).thenReturn(userInfo);
 
 		schedulerJobService.stopExploratoryByScheduler();
 
 		verify(securityService).getServiceAccountInfo(USER);
 		verify(schedulerJobDAO).getExploratorySchedulerWithStatusAndClusterLastActivityLessThan(eq(RUNNING),
 				any(Date.class));
-		verify(exploratoryService).stop(refEq(getUserInfo()), eq(PROJECT), eq(EXPLORATORY_NAME));
+		verify(exploratoryService).stop(refEq(userInfo), eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME), eq(Collections.singletonList(AUDIT_MESSAGE)));
 		verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService);
 	}
 
@@ -711,9 +713,9 @@ public class SchedulerJobServiceImplTest {
 
 		verify(securityService).getServiceAccountInfo(USER);
 		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT));
+		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(Collections.singletonList(AUDIT_MESSAGE)));
 		verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT));
+		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(Collections.singletonList(AUDIT_MESSAGE)));
 		verifyNoMoreInteractions(schedulerJobDAO, exploratoryService);
 		verifyZeroInteractions(computationalService, computationalDAO);
 	}
@@ -737,7 +739,7 @@ public class SchedulerJobServiceImplTest {
 
 		verify(securityService, times(2)).getServiceAccountInfo(USER);
 		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT));
+		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(Collections.singletonList(AUDIT_MESSAGE)));
 		verify(computationalDAO).findComputationalResourcesWithStatus(USER, PROJECT, EXPLORATORY_NAME, STOPPED);
 		verify(computationalService).startSparkCluster(refEq(getUserInfo()), eq(EXPLORATORY_NAME),
 				eq(COMPUTATIONAL_NAME), eq(PROJECT));
@@ -764,7 +766,7 @@ public class SchedulerJobServiceImplTest {
 
 		verify(securityService).getServiceAccountInfo(USER);
 		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT));
+		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(Collections.singletonList(AUDIT_MESSAGE)));
 		verify(computationalDAO).findComputationalResourcesWithStatus(USER, PROJECT, EXPLORATORY_NAME, STOPPED);
 		verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService, computationalDAO);
 		verifyZeroInteractions(computationalService);
@@ -789,7 +791,7 @@ public class SchedulerJobServiceImplTest {
 
 		verify(securityService).getServiceAccountInfo(USER);
 		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT));
+		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(PROJECT), eq(Collections.singletonList(AUDIT_MESSAGE)));
 		verify(computationalDAO).findComputationalResourcesWithStatus(USER, PROJECT, EXPLORATORY_NAME, STOPPED);
 		verifyNoMoreInteractions(securityService, schedulerJobDAO, exploratoryService, computationalDAO);
 		verifyZeroInteractions(computationalService);
@@ -974,7 +976,7 @@ public class SchedulerJobServiceImplTest {
 
 		verify(securityService).getUserInfoOffline(USER);
 		verify(schedulerJobDAO).getExploratorySchedulerDataWithOneOfStatus(RUNNING, STOPPED);
-		verify(exploratoryService).terminate(refEq(getUserInfo()), eq(PROJECT), eq(EXPLORATORY_NAME));
+		verify(exploratoryService).terminate(refEq(getUserInfo()), eq(USER), eq(PROJECT), eq(EXPLORATORY_NAME), eq(Collections.singletonList(AUDIT_MESSAGE)));
 		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService, exploratoryService);
 	}
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@dlab.apache.org
For additional commands, e-mail: commits-help@dlab.apache.org