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:39 UTC

[incubator-dlab] branch audit updated (e6d4e5d -> 6560b6c)

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

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


    from e6d4e5d  [DLAB-1758]: Merge audit UI (#784)
     new 16ae6ac  Added audit support for projects
     new 809fa37  Added audit support for notebooks
     new b4291ee  Added audit endpoint
     new 2c5c0f7  Added endpoint to retrieve audit
     new 8032353  Merge remote-tracking branch 'origin/audit' into audit
     new 66f49da  Merge remote-tracking branch 'origin/audit' into audit
     new 6560b6c  Added audit for computational resources

The 7 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../java/com/epam/dlab/util/UsernameUtils.java     |   2 +-
 .../epam/dlab/rest/contracts/ComputationalAPI.java |   1 +
 .../azure/ComputationalResourceAzure.java          |   2 +-
 .../dlab/backendapi/SelfServiceApplication.java    |  39 +++++-
 .../com/epam/dlab/backendapi/dao/AuditDAO.java     |   8 +-
 .../com/epam/dlab/backendapi/dao/AuditDAOImpl.java |  11 +-
 .../dlab/backendapi/domain/AuditActionEnum.java    |   5 +-
 .../dlab/backendapi/domain/AuditCreateDTO.java     |  10 +-
 .../com/epam/dlab/backendapi/domain/AuditDTO.java  |   8 +-
 .../backendapi/interceptor/AuditInterceptor.java   |   6 +-
 .../dlab/backendapi/resources/AuditResource.java}  |  32 +++--
 .../backendapi/resources/ExploratoryResource.java  |   8 +-
 .../resources/aws/ComputationalResourceAws.java    |  10 +-
 .../azure/ComputationalResourceAzure.java          |  10 +-
 .../resources/gcp/ComputationalResourceGcp.java    |  40 +++---
 .../epam/dlab/backendapi/service/AuditService.java |   9 +-
 .../backendapi/service/ComputationalService.java   |  19 +--
 .../backendapi/service/ExploratoryService.java     |   8 +-
 .../backendapi/service/impl/AuditServiceImpl.java  |  23 +++-
 .../service/impl/ComputationalServiceImpl.java     |  45 ++++---
 .../service/impl/EnvironmentServiceImpl.java       |  25 ++--
 .../service/impl/ExploratoryServiceImpl.java       | 108 ++++++++--------
 .../service/impl/ProjectServiceImpl.java           |  15 ++-
 .../service/impl/SchedulerJobServiceImpl.java      |  26 ++--
 .../epam/dlab/backendapi/util/RequestBuilder.java  | 136 ++++++++++----------
 .../resources/ExploratoryResourceTest.java         | 142 +++++++++------------
 .../service/impl/ComputationalServiceImplTest.java |  63 ++++-----
 .../service/impl/EnvironmentServiceImplTest.java   |  31 +++--
 .../service/impl/ExploratoryServiceImplTest.java   |  84 ++++++------
 .../service/impl/SchedulerJobServiceImplTest.java  |  63 ++++-----
 30 files changed, 554 insertions(+), 435 deletions(-)
 copy services/{provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ProvisioningHealthCheckResource.java => self-service/src/main/java/com/epam/dlab/backendapi/resources/AuditResource.java} (58%)


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


[incubator-dlab] 01/07: Added audit support for projects

Posted by of...@apache.org.
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 16ae6acdcdf9aedd73ebb04b3e9c43a50196cdb1
Author: Oleh Fuks <ol...@gmail.com>
AuthorDate: Mon May 4 17:44:34 2020 +0300

    Added audit support for projects
---
 services/self-service/self-service.yml             |   4 +-
 .../com/epam/dlab/backendapi/annotation/Audit.java |  33 +++++++
 .../com/epam/dlab/backendapi/annotation/Info.java  |  30 ++++++
 .../dlab/backendapi/annotation/ResourceName.java   |  30 ++++++
 .../conf/SelfServiceApplicationConfiguration.java  |   7 ++
 .../com/epam/dlab/backendapi/dao/AuditDAO.java     |  26 ++++++
 .../com/epam/dlab/backendapi/dao/AuditDAOImpl.java |  31 ++++++
 .../java/com/epam/dlab/backendapi/dao/BaseDAO.java |   2 +
 .../dlab/backendapi/domain/AuditActionEnum.java    |  24 +++++
 .../AuditCreateDTO.java}                           |  42 ++-------
 .../com/epam/dlab/backendapi/domain/AuditDTO.java  |  32 +++++++
 .../backendapi/interceptor/AuditInterceptor.java   | 100 ++++++++++++++++++++
 .../backendapi/modules/CloudProviderModule.java    |  11 ++-
 .../epam/dlab/backendapi/modules/DevModule.java    |   6 ++
 .../dlab/backendapi/modules/ProductionModule.java  |   6 ++
 .../dlab/backendapi/resources/ProjectResource.java |   8 +-
 .../resources/dto/HealthStatusPageDTO.java         |   2 +
 .../epam/dlab/backendapi/service/AuditService.java |  26 ++++++
 .../dlab/backendapi/service/ProjectService.java    |   5 +-
 .../backendapi/service/impl/AuditServiceImpl.java  |  39 ++++++++
 .../impl/InfrastructureInfoServiceImpl.java        |   1 +
 .../service/impl/ProjectServiceImpl.java           | 104 +++++++++++++++++----
 22 files changed, 505 insertions(+), 64 deletions(-)

diff --git a/services/self-service/self-service.yml b/services/self-service/self-service.yml
index df92c25..f4117ff 100644
--- a/services/self-service/self-service.yml
+++ b/services/self-service/self-service.yml
@@ -50,8 +50,10 @@ roleDefaultAccess: true
 
 # Set to true to enable the scheduler of billing report.
 billingSchedulerEnabled: false
+# Set to true to enable audit
+auditEnabled: true
 # Name of configuration file for billing report.
-<#if DEV_MODE == "true">
+  <#if DEV_MODE == "true">
 billingConfFile: ${sys['user.dir']}/../billing/billing.yml
 <#else>
 billingConfFile: ${DLAB_CONF_DIR}/billing.yml
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Audit.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Audit.java
new file mode 100644
index 0000000..d6bd5e9
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Audit.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.annotation;
+
+import com.epam.dlab.backendapi.domain.AuditActionEnum;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Audit {
+    AuditActionEnum action();
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Info.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Info.java
new file mode 100644
index 0000000..44ca32b
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Info.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Info {
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/ResourceName.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/ResourceName.java
new file mode 100644
index 0000000..100df0d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/ResourceName.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ResourceName {
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/conf/SelfServiceApplicationConfiguration.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/conf/SelfServiceApplicationConfiguration.java
index aaface6..7d0e874 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/conf/SelfServiceApplicationConfiguration.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/conf/SelfServiceApplicationConfiguration.java
@@ -78,6 +78,9 @@ public class SelfServiceApplicationConfiguration extends ServiceConfiguration {
 	@JsonProperty
 	private boolean billingSchedulerEnabled = false;
 
+	@JsonProperty
+	private boolean auditEnabled = false;
+
 	@NotEmpty
 	@JsonProperty
 	private String billingConfFile;
@@ -202,6 +205,10 @@ public class SelfServiceApplicationConfiguration extends ServiceConfiguration {
 		return billingSchedulerEnabled;
 	}
 
+	public boolean isAuditEnabled() {
+		return auditEnabled;
+	}
+
 	/**
 	 * Return the default access to DLab features using roles policy.
 	 */
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java
new file mode 100644
index 0000000..b9a7727
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.dao;
+
+import com.epam.dlab.backendapi.domain.AuditCreateDTO;
+
+public interface AuditDAO {
+    void save(AuditCreateDTO audit);
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java
new file mode 100644
index 0000000..2de30aa
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.dao;
+
+import com.epam.dlab.backendapi.domain.AuditCreateDTO;
+
+public class AuditDAOImpl extends BaseDAO implements AuditDAO {
+    private final static String AUDIT_COLLECTION = "audit";
+
+    @Override
+    public void save(AuditCreateDTO audit) {
+        insertOne(AUDIT_COLLECTION, audit);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseDAO.java
index c2ff69b..96532a5 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseDAO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseDAO.java
@@ -28,6 +28,7 @@ import com.epam.dlab.util.mongo.modules.MongoModule;
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
 import com.google.inject.Inject;
 import com.mongodb.BasicDBObject;
 import com.mongodb.MongoException;
@@ -69,6 +70,7 @@ public class BaseDAO {
 
 	private static final ObjectMapper MAPPER = new ObjectMapper()
 			.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true)
+			.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
 			.registerModule(new IsoDateModule())
 			.registerModule(new JavaPrimitiveModule())
 			.registerModule(new MongoModule());
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
new file mode 100644
index 0000000..7a02a79
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditActionEnum.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.domain;
+
+public enum AuditActionEnum {
+    CREATE_PROJECT, START_PROJECT, STOP_PROJECT, TERMINATE_PROJECT, UPDATE_PROJECT
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditCreateDTO.java
similarity index 51%
copy from services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java
copy to services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditCreateDTO.java
index 4eb0b3b..de40808 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditCreateDTO.java
@@ -17,45 +17,19 @@
  * under the License.
  */
 
-package com.epam.dlab.backendapi.resources.dto;
+package com.epam.dlab.backendapi.domain;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Builder;
 import lombok.Data;
 
 import java.util.List;
 
-/**
- * Stores the health statuses for environment resources.
- */
+
 @Data
 @Builder
-public class HealthStatusPageDTO {
-	@JsonProperty
-	private String status;
-	@JsonProperty("list_resources")
-	private List<HealthStatusResource> listResources;
-	@JsonProperty
-	private boolean billingEnabled;
-	@JsonProperty
-	private boolean admin;
-	@JsonProperty
-	private boolean projectAdmin;
-	@JsonProperty
-	private int billingQuoteUsed;
-	@JsonProperty
-	private int billingUserQuoteUsed;
-	@JsonProperty
-	private boolean projectAssigned;
-	@JsonProperty
-	private BucketBrowser bucketBrowser;
-
-	@Builder
-	@Data
-	public static class BucketBrowser {
-		private final boolean view;
-		private final boolean upload;
-		private final boolean download;
-		private final boolean delete;
-	}
-}
\ No newline at end of file
+public class AuditCreateDTO {
+    private final String user;
+    private final AuditActionEnum action;
+    private final String resourceName;
+    private final List<String> info;
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java
new file mode 100644
index 0000000..2a337e5
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.domain;
+
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class AuditDTO {
+    private final String user;
+    private final AuditActionEnum action;
+    private final String resourceName;
+    private final Date date;
+}
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
new file mode 100644
index 0000000..20a42d7
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/AuditInterceptor.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.interceptor;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.annotation.Audit;
+import com.epam.dlab.backendapi.annotation.Info;
+import com.epam.dlab.backendapi.annotation.ResourceName;
+import com.epam.dlab.backendapi.annotation.User;
+import com.epam.dlab.backendapi.domain.AuditActionEnum;
+import com.epam.dlab.backendapi.domain.AuditCreateDTO;
+import com.epam.dlab.backendapi.service.AuditService;
+import com.epam.dlab.exceptions.DlabException;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.IntStream;
+
+@Slf4j
+public class AuditInterceptor implements MethodInterceptor {
+    @Inject
+    private AuditService auditService;
+
+    @Override
+    public Object invoke(MethodInvocation mi) throws Throwable {
+        Method method = mi.getMethod();
+        final Parameter[] parameters = mi.getMethod().getParameters();
+        final String user = getUserInfo(mi, parameters);
+        final AuditActionEnum action = getAuditActionEnum(method);
+        final String resourceName = getResourceName(mi, parameters);
+        final List<String> infoMap = getInfo(mi, parameters);
+
+        AuditCreateDTO auditCreateDTO = AuditCreateDTO.builder()
+                .user(user)
+                .action(action)
+                .resourceName(resourceName)
+                .info(infoMap)
+                .build();
+        auditService.save(auditCreateDTO);
+        return mi.proceed();
+    }
+
+    private String getUserInfo(MethodInvocation mi, Parameter[] parameters) {
+        return IntStream.range(0, parameters.length)
+                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(User.class)))
+                .mapToObj(i -> ((UserInfo) mi.getArguments()[i]).getName())
+                .findAny()
+                .orElseThrow(() -> new DlabException("UserInfo parameter wanted!"));
+    }
+
+    private AuditActionEnum getAuditActionEnum(Method method) {
+        Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
+        return IntStream.range(0, method.getDeclaredAnnotations().length)
+                .filter(i -> declaredAnnotations[i] instanceof Audit)
+                .mapToObj(i -> ((Audit) declaredAnnotations[i]).action())
+                .findAny()
+                .orElseThrow(() -> new DlabException("'Audit' annotation wanted!"));
+    }
+
+    private String getResourceName(MethodInvocation mi, Parameter[] parameters) {
+        return IntStream.range(0, parameters.length)
+                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(ResourceName.class)))
+                .mapToObj(i -> (String) mi.getArguments()[i])
+                .findAny()
+                .orElseThrow(() -> new DlabException("Resource name parameter wanted!"));
+    }
+
+    private List<String> getInfo(MethodInvocation mi, Parameter[] parameters) {
+        return IntStream.range(0, parameters.length)
+                .filter(i -> Objects.nonNull(parameters[i].getAnnotation(Info.class)))
+                .mapToObj(i -> (List<String>) mi.getArguments()[i])
+                .findAny()
+                .orElseGet(Collections::emptyList);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/CloudProviderModule.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/CloudProviderModule.java
index f75f877..f49c98d 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/CloudProviderModule.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/CloudProviderModule.java
@@ -20,9 +20,11 @@
 package com.epam.dlab.backendapi.modules;
 
 import com.epam.dlab.backendapi.SelfServiceApplication;
+import com.epam.dlab.backendapi.annotation.Audit;
 import com.epam.dlab.backendapi.annotation.BudgetLimited;
 import com.epam.dlab.backendapi.annotation.ProjectAdmin;
 import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.dlab.backendapi.interceptor.AuditInterceptor;
 import com.epam.dlab.backendapi.interceptor.BudgetLimitInterceptor;
 import com.epam.dlab.backendapi.interceptor.ProjectAdminInterceptor;
 import com.epam.dlab.backendapi.resources.BillingResource;
@@ -72,11 +74,16 @@ public class CloudProviderModule extends CloudModule {
                 new SchedulerConfiguration(SelfServiceApplication.class.getPackage().getName()));
 
         final BudgetLimitInterceptor budgetLimitInterceptor = new BudgetLimitInterceptor();
-        final ProjectAdminInterceptor projectAdminInterceptor = new ProjectAdminInterceptor();
         requestInjection(budgetLimitInterceptor);
-        requestInjection(projectAdminInterceptor);
         bindInterceptor(any(), annotatedWith(BudgetLimited.class), budgetLimitInterceptor);
+        final ProjectAdminInterceptor projectAdminInterceptor = new ProjectAdminInterceptor();
+        requestInjection(projectAdminInterceptor);
         bindInterceptor(any(), annotatedWith(ProjectAdmin.class), projectAdminInterceptor);
+        if (configuration.isAuditEnabled()) {
+            final AuditInterceptor auditInterceptor = new AuditInterceptor();
+            requestInjection(auditInterceptor);
+            bindInterceptor(any(), annotatedWith(Audit.class), auditInterceptor);
+        }
     }
 
     @Override
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
index 31b4056..5c8f9bf 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
@@ -23,6 +23,8 @@ import com.epam.dlab.ModuleBase;
 import com.epam.dlab.auth.contract.SecurityAPI;
 import com.epam.dlab.backendapi.auth.SelfServiceSecurityAuthorizer;
 import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.dlab.backendapi.dao.AuditDAO;
+import com.epam.dlab.backendapi.dao.AuditDAOImpl;
 import com.epam.dlab.backendapi.dao.BackupDao;
 import com.epam.dlab.backendapi.dao.BackupDaoImpl;
 import com.epam.dlab.backendapi.dao.BaseBillingDAO;
@@ -40,6 +42,7 @@ import com.epam.dlab.backendapi.dao.UserRoleDaoImpl;
 import com.epam.dlab.backendapi.service.AccessKeyService;
 import com.epam.dlab.backendapi.service.ApplicationSettingService;
 import com.epam.dlab.backendapi.service.ApplicationSettingServiceImpl;
+import com.epam.dlab.backendapi.service.AuditService;
 import com.epam.dlab.backendapi.service.BackupService;
 import com.epam.dlab.backendapi.service.BucketService;
 import com.epam.dlab.backendapi.service.ComputationalService;
@@ -68,6 +71,7 @@ import com.epam.dlab.backendapi.service.UserRoleServiceImpl;
 import com.epam.dlab.backendapi.service.UserSettingService;
 import com.epam.dlab.backendapi.service.UserSettingServiceImpl;
 import com.epam.dlab.backendapi.service.impl.AccessKeyServiceImpl;
+import com.epam.dlab.backendapi.service.impl.AuditServiceImpl;
 import com.epam.dlab.backendapi.service.impl.BackupServiceImpl;
 import com.epam.dlab.backendapi.service.impl.BucketServiceImpl;
 import com.epam.dlab.backendapi.service.impl.ComputationalServiceImpl;
@@ -170,8 +174,10 @@ public class DevModule extends ModuleBase<SelfServiceApplicationConfiguration> i
 		bind(EndpointService.class).to(EndpointServiceImpl.class);
 		bind(EndpointDAO.class).to(EndpointDAOImpl.class);
 		bind(ProjectService.class).to(ProjectServiceImpl.class);
+		bind(AuditService.class).to(AuditServiceImpl.class);
 		bind(ProjectDAO.class).to(ProjectDAOImpl.class);
 		bind(BillingDAO.class).to(BaseBillingDAO.class);
+		bind(AuditDAO.class).to(AuditDAOImpl.class);
 		bind(BucketService.class).to(BucketServiceImpl.class);
 	}
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
index 5fb314d..901a61f 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
@@ -22,6 +22,8 @@ package com.epam.dlab.backendapi.modules;
 import com.epam.dlab.ModuleBase;
 import com.epam.dlab.backendapi.auth.SelfServiceSecurityAuthorizer;
 import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.epam.dlab.backendapi.dao.AuditDAO;
+import com.epam.dlab.backendapi.dao.AuditDAOImpl;
 import com.epam.dlab.backendapi.dao.BackupDao;
 import com.epam.dlab.backendapi.dao.BackupDaoImpl;
 import com.epam.dlab.backendapi.dao.BaseBillingDAO;
@@ -39,6 +41,7 @@ import com.epam.dlab.backendapi.dao.UserRoleDaoImpl;
 import com.epam.dlab.backendapi.service.AccessKeyService;
 import com.epam.dlab.backendapi.service.ApplicationSettingService;
 import com.epam.dlab.backendapi.service.ApplicationSettingServiceImpl;
+import com.epam.dlab.backendapi.service.AuditService;
 import com.epam.dlab.backendapi.service.BackupService;
 import com.epam.dlab.backendapi.service.BucketService;
 import com.epam.dlab.backendapi.service.ComputationalService;
@@ -67,6 +70,7 @@ import com.epam.dlab.backendapi.service.UserRoleServiceImpl;
 import com.epam.dlab.backendapi.service.UserSettingService;
 import com.epam.dlab.backendapi.service.UserSettingServiceImpl;
 import com.epam.dlab.backendapi.service.impl.AccessKeyServiceImpl;
+import com.epam.dlab.backendapi.service.impl.AuditServiceImpl;
 import com.epam.dlab.backendapi.service.impl.BackupServiceImpl;
 import com.epam.dlab.backendapi.service.impl.BucketServiceImpl;
 import com.epam.dlab.backendapi.service.impl.ComputationalServiceImpl;
@@ -159,8 +163,10 @@ public class ProductionModule extends ModuleBase<SelfServiceApplicationConfigura
 		bind(EndpointService.class).to(EndpointServiceImpl.class);
 		bind(EndpointDAO.class).to(EndpointDAOImpl.class);
 		bind(ProjectService.class).to(ProjectServiceImpl.class);
+		bind(AuditService.class).to(AuditServiceImpl.class);
 		bind(ProjectDAO.class).to(ProjectDAOImpl.class);
 		bind(BillingDAO.class).to(BaseBillingDAO.class);
+		bind(AuditDAO.class).to(AuditDAOImpl.class);
 		bind(BucketService.class).to(BucketServiceImpl.class);
 		bind(TagService.class).to(TagServiceImpl.class);
 		bind(SecurityService.class).to(SecurityServiceImpl.class);
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
index 7b26d73..6d93e89 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
@@ -76,7 +76,7 @@ public class ProjectResource {
 		projectService.create(userInfo, new ProjectDTO(projectDTO.getName(), projectDTO.getGroups(),
 				projectDTO.getKey(), projectDTO.getTag(), null,
 				projectDTO.getEndpoints().stream().map(e -> new ProjectEndpointDTO(e, UserInstanceStatus.CREATING,
-						null)).collect(Collectors.toList()), projectDTO.isSharedImageEnabled()));
+						null)).collect(Collectors.toList()), projectDTO.isSharedImageEnabled()), projectDTO.getName());
 		final URI uri = uriInfo.getRequestUriBuilder().path(projectDTO.getName()).build();
 		return Response
 				.ok()
@@ -222,11 +222,7 @@ public class ProjectResource {
 			@Parameter(hidden = true) @Auth UserInfo userInfo,
 			@Parameter(description = "Project name")
 					List<UpdateProjectBudgetDTO> dtos) {
-		final List<ProjectDTO> projects = dtos
-				.stream()
-				.map(dto -> ProjectDTO.builder().name(dto.getProject()).budget(dto.getBudget()).build())
-				.collect(Collectors.toList());
-		projectService.updateBudget(projects);
+		projectService.updateBudget(userInfo, dtos);
 		return Response.ok().build();
 	}
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java
index 4eb0b3b..642dd06 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java
@@ -38,6 +38,8 @@ public class HealthStatusPageDTO {
 	@JsonProperty
 	private boolean billingEnabled;
 	@JsonProperty
+	private boolean auditEnabled;
+	@JsonProperty
 	private boolean admin;
 	@JsonProperty
 	private boolean projectAdmin;
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java
new file mode 100644
index 0000000..b7f4fce
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.service;
+
+import com.epam.dlab.backendapi.domain.AuditCreateDTO;
+
+public interface AuditService {
+    void save(AuditCreateDTO audit);
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
index fa0aedc..953caef 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
@@ -2,6 +2,7 @@ package com.epam.dlab.backendapi.service;
 
 import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.domain.ProjectDTO;
+import com.epam.dlab.backendapi.domain.UpdateProjectBudgetDTO;
 import com.epam.dlab.backendapi.domain.UpdateProjectDTO;
 
 import java.util.List;
@@ -15,7 +16,7 @@ public interface ProjectService {
 
 	List<ProjectDTO> getProjectsByEndpoint(String endpointName);
 
-	void create(UserInfo userInfo, ProjectDTO projectDTO);
+	void create(UserInfo userInfo, ProjectDTO projectDTO, String resourceName);
 
 	ProjectDTO get(String name);
 
@@ -33,7 +34,7 @@ public interface ProjectService {
 
 	void update(UserInfo userInfo, UpdateProjectDTO projectDTO, String projectName);
 
-	void updateBudget(List<ProjectDTO> projects);
+	void updateBudget(UserInfo userInfo, List<UpdateProjectBudgetDTO> projects);
 
 	boolean isAnyProjectAssigned(UserInfo userInfo);
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java
new file mode 100644
index 0000000..d73460b
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.dlab.backendapi.service.impl;
+
+import com.epam.dlab.backendapi.dao.AuditDAO;
+import com.epam.dlab.backendapi.domain.AuditCreateDTO;
+import com.epam.dlab.backendapi.service.AuditService;
+import com.google.inject.Inject;
+
+public class AuditServiceImpl implements AuditService {
+    private final AuditDAO auditDAO;
+
+    @Inject
+    public AuditServiceImpl(AuditDAO auditDAO) {
+        this.auditDAO = auditDAO;
+    }
+
+    @Override
+    public void save(AuditCreateDTO audit) {
+        auditDAO.save(audit);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceImpl.java
index 4063ca1..08ce7b9 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceImpl.java
@@ -133,6 +133,7 @@ public class InfrastructureInfoServiceImpl implements InfrastructureInfoService
 					.status(HealthStatusEnum.OK.toString())
 					.listResources(Collections.emptyList())
 					.billingEnabled(configuration.isBillingSchedulerEnabled())
+					.auditEnabled(configuration.isAuditEnabled())
 					.projectAdmin(UserRoles.isProjectAdmin(userInfo))
 					.admin(UserRoles.isAdmin(userInfo))
 					.projectAssigned(projectService.isAnyProjectAssigned(userInfo))
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 0d1f5ed..9658897 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
@@ -1,10 +1,14 @@
 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.ProjectAdmin;
+import com.epam.dlab.backendapi.annotation.ResourceName;
 import com.epam.dlab.backendapi.annotation.User;
+import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
 import com.epam.dlab.backendapi.dao.ExploratoryDAO;
 import com.epam.dlab.backendapi.dao.ProjectDAO;
 import com.epam.dlab.backendapi.dao.UserGroupDao;
@@ -12,12 +16,12 @@ import com.epam.dlab.backendapi.domain.EndpointDTO;
 import com.epam.dlab.backendapi.domain.ProjectDTO;
 import com.epam.dlab.backendapi.domain.ProjectEndpointDTO;
 import com.epam.dlab.backendapi.domain.RequestId;
+import com.epam.dlab.backendapi.domain.UpdateProjectBudgetDTO;
 import com.epam.dlab.backendapi.domain.UpdateProjectDTO;
 import com.epam.dlab.backendapi.roles.UserRoles;
 import com.epam.dlab.backendapi.service.EndpointService;
 import com.epam.dlab.backendapi.service.ExploratoryService;
 import com.epam.dlab.backendapi.service.ProjectService;
-import com.epam.dlab.backendapi.service.SecurityService;
 import com.epam.dlab.backendapi.util.RequestBuilder;
 import com.epam.dlab.constants.ServiceConsts;
 import com.epam.dlab.dto.UserInstanceStatus;
@@ -28,13 +32,20 @@ import com.google.inject.Inject;
 import com.google.inject.name.Named;
 import lombok.extern.slf4j.Slf4j;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.CREATE_PROJECT;
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.START_PROJECT;
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.STOP_PROJECT;
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.TERMINATE_PROJECT;
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.UPDATE_PROJECT;
 import static java.util.stream.Collectors.toSet;
 import static java.util.stream.Stream.concat;
 
@@ -46,7 +57,11 @@ public class ProjectServiceImpl implements ProjectService {
 	private static final String START_PRJ_API = "infrastructure/project/start";
 	private static final String STOP_PRJ_API = "infrastructure/project/stop";
 	private static final String STOP_ACTION = "stop";
-	private static final String TERMINATE_ACTION = "terminate";
+
+	private static final String AUDIT_ADD_ENDPOINT = "Added endpoint(s) %s";
+	private static final String AUDIT_ADD_GROUP = "Added group(s) %s";
+	private static final String AUDIT_REMOVE_GROUP = "Removed group(s) %s";
+	private static final String AUDIT_UPDATE_BUDGET = "Update budget %d->%d";
 
 	private final ProjectDAO projectDAO;
 	private final ExploratoryService exploratoryService;
@@ -56,14 +71,15 @@ public class ProjectServiceImpl implements ProjectService {
 	private final RequestBuilder requestBuilder;
 	private final EndpointService endpointService;
 	private final ExploratoryDAO exploratoryDAO;
-	private final SecurityService securityService;
+	private final SelfServiceApplicationConfiguration configuration;
+
 
 	@Inject
 	public ProjectServiceImpl(ProjectDAO projectDAO, ExploratoryService exploratoryService,
 							  UserGroupDao userGroupDao,
 							  @Named(ServiceConsts.PROVISIONING_SERVICE_NAME) RESTService provisioningService,
 							  RequestId requestId, RequestBuilder requestBuilder, EndpointService endpointService,
-							  ExploratoryDAO exploratoryDAO, SecurityService securityService) {
+							  ExploratoryDAO exploratoryDAO, SelfServiceApplicationConfiguration configuration) {
 		this.projectDAO = projectDAO;
 		this.exploratoryService = exploratoryService;
 		this.userGroupDao = userGroupDao;
@@ -72,7 +88,7 @@ public class ProjectServiceImpl implements ProjectService {
 		this.requestBuilder = requestBuilder;
 		this.endpointService = endpointService;
 		this.exploratoryDAO = exploratoryDAO;
-		this.securityService = securityService;
+		this.configuration = configuration;
 	}
 
 	@Override
@@ -100,7 +116,8 @@ public class ProjectServiceImpl implements ProjectService {
 
 	@BudgetLimited
 	@Override
-	public void create(UserInfo user, ProjectDTO projectDTO) {
+	@Audit(action = CREATE_PROJECT)
+	public void create(@User UserInfo user, ProjectDTO projectDTO, @ResourceName String resourceName) {
 		if (!projectDAO.get(projectDTO.getName()).isPresent()) {
 			projectDAO.create(projectDTO);
 			createProjectOnCloud(user, projectDTO);
@@ -123,9 +140,9 @@ public class ProjectServiceImpl implements ProjectService {
 	}
 
 	@ProjectAdmin
+	@Audit(action = TERMINATE_PROJECT)
 	@Override
-	public void terminateEndpoint(@User UserInfo userInfo, List<String> endpoints, @Project String name) {
-		System.out.println("sd");
+	public void terminateEndpoint(@User UserInfo userInfo, List<String> endpoints, @ResourceName @Project String name) {
 		endpoints.forEach(endpoint -> terminateEndpoint(userInfo, endpoint, name));
 	}
 
@@ -137,8 +154,9 @@ public class ProjectServiceImpl implements ProjectService {
 	}
 
 	@ProjectAdmin
+	@Audit(action = START_PROJECT)
 	@Override
-	public void start(@User UserInfo userInfo, List<String> endpoints, @Project String name) {
+	public void start(@User UserInfo userInfo, List<String> endpoints, @ResourceName @Project String name) {
 		endpoints.forEach(endpoint -> start(userInfo, endpoint, name));
 	}
 
@@ -149,8 +167,9 @@ public class ProjectServiceImpl implements ProjectService {
 	}
 
 	@ProjectAdmin
+	@Audit(action = STOP_PROJECT)
 	@Override
-	public void stopWithResources(@User UserInfo userInfo, List<String> endpoints, @Project String projectName) {
+	public void stopWithResources(@User UserInfo userInfo, List<String> endpoints, @ResourceName @Project String projectName) {
 		List<ProjectEndpointDTO> endpointDTOs = get(projectName)
 				.getEndpoints()
 				.stream()
@@ -165,8 +184,10 @@ public class ProjectServiceImpl implements ProjectService {
 						.collect(Collectors.toList()))
 				.forEach(e -> exploratoryService.stop(new UserInfo(e.getUser(), userInfo.getAccessToken()), projectName, e.getExploratoryName()));
 
-		endpointDTOs.stream().filter(e -> !Arrays.asList(UserInstanceStatus.TERMINATED,
-				UserInstanceStatus.TERMINATING, UserInstanceStatus.STOPPED, UserInstanceStatus.FAILED).contains(e.getStatus()))
+		endpointDTOs
+				.stream()
+				.filter(e -> !Arrays.asList(UserInstanceStatus.TERMINATED, UserInstanceStatus.TERMINATING, UserInstanceStatus.STOPPED,
+						UserInstanceStatus.FAILED).contains(e.getStatus()))
 				.forEach(e -> stop(userInfo, e.getName(), projectName));
 	}
 
@@ -178,9 +199,17 @@ public class ProjectServiceImpl implements ProjectService {
 				.stream()
 				.map(ProjectEndpointDTO::getName)
 				.collect(toSet());
-		final HashSet<String> newEndpoints = new HashSet<>(projectDTO.getEndpoints());
+		final Set<String> newEndpoints = new HashSet<>(projectDTO.getEndpoints());
 		newEndpoints.removeAll(endpoints);
-		final List<ProjectEndpointDTO> endpointsToBeCreated = newEndpoints.stream()
+		final List<String> projectAudit = updateProjectAudit(projectDTO, project, newEndpoints);
+		updateProject(userInfo, projectName, projectDTO, project, newEndpoints, projectAudit);
+	}
+
+	@Audit(action = UPDATE_PROJECT)
+	public void updateProject(@User UserInfo userInfo, @ResourceName String projectName, UpdateProjectDTO projectDTO, ProjectDTO project, Set<String> newEndpoints,
+							  @Info List<String> projectAudit) {
+		final List<ProjectEndpointDTO> endpointsToBeCreated = newEndpoints
+				.stream()
 				.map(e -> new ProjectEndpointDTO(e, UserInstanceStatus.CREATING, null))
 				.collect(Collectors.toList());
 		project.getEndpoints().addAll(endpointsToBeCreated);
@@ -190,8 +219,18 @@ public class ProjectServiceImpl implements ProjectService {
 	}
 
 	@Override
-	public void updateBudget(List<ProjectDTO> projects) {
-		projects.forEach(p -> projectDAO.updateBudget(p.getName(), p.getBudget()));
+	public void updateBudget(UserInfo userInfo, List<UpdateProjectBudgetDTO> dtos) {
+		final List<ProjectDTO> projects = dtos
+				.stream()
+				.map(dto -> ProjectDTO.builder().name(dto.getProject()).budget(dto.getBudget()).build())
+				.collect(Collectors.toList());
+
+		projects.forEach(p -> updateBudget(userInfo, p.getName(), p.getBudget(), getUpdateBudgetAudit(p)));
+	}
+
+	@Audit(action = UPDATE_PROJECT)
+	public void updateBudget(@User UserInfo userInfo, @ResourceName String name, Integer budget, @Info List<String> updateBudgetAudit) {
+		projectDAO.updateBudget(name, budget);
 	}
 
 	@Override
@@ -243,9 +282,10 @@ public class ProjectServiceImpl implements ProjectService {
 	}
 
 	private void checkProjectRelatedResourcesInProgress(String projectName, List<ProjectEndpointDTO> endpoints, String action) {
-        boolean edgeProgress = endpoints.stream().anyMatch(e ->
-                Arrays.asList(UserInstanceStatus.CREATING, UserInstanceStatus.STARTING, UserInstanceStatus.STOPPING,
-                        UserInstanceStatus.TERMINATING).contains(e.getStatus()));
+		boolean edgeProgress = endpoints
+				.stream().anyMatch(e ->
+						Arrays.asList(UserInstanceStatus.CREATING, UserInstanceStatus.STARTING, UserInstanceStatus.STOPPING,
+								UserInstanceStatus.TERMINATING).contains(e.getStatus()));
 
 		List<String> endpointsName = endpoints.stream().map(ProjectEndpointDTO::getName).collect(Collectors.toList());
 		if (edgeProgress || !checkExploratoriesAndComputationalProgress(projectName, endpointsName)) {
@@ -254,6 +294,32 @@ public class ProjectServiceImpl implements ProjectService {
 		}
 	}
 
+	private List<String> updateProjectAudit(UpdateProjectDTO projectDTO, ProjectDTO project, Set<String> newEndpoints) {
+		if (configuration.isAuditEnabled()) {
+			return null;
+		}
+		final List<String> audit = new ArrayList<>();
+		final Set<String> newGroups = new HashSet<>(projectDTO.getGroups());
+		newGroups.removeAll(project.getGroups());
+		final Set<String> removedGroups = new HashSet<>(project.getGroups());
+		removedGroups.removeAll(projectDTO.getGroups());
+
+		if (!newEndpoints.isEmpty()) {
+			audit.add(String.format(AUDIT_ADD_ENDPOINT, String.join(", ", newEndpoints)));
+		}
+		if (!newGroups.isEmpty()) {
+			audit.add(String.format(AUDIT_ADD_GROUP, String.join(", ", newGroups)));
+		}
+		if (!removedGroups.isEmpty()) {
+			audit.add(String.format(AUDIT_REMOVE_GROUP, String.join(", ", removedGroups)));
+		}
+		return audit;
+	}
+
+	private List<String> getUpdateBudgetAudit(ProjectDTO p) {
+		return Collections.singletonList(String.format(AUDIT_UPDATE_BUDGET, get(p.getName()).getBudget(), p.getBudget()));
+	}
+
 	private Supplier<ResourceNotFoundException> projectNotFound() {
 		return () -> new ResourceNotFoundException("Project with passed name not found");
 	}


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


[incubator-dlab] 07/07: Added audit for computational resources

Posted by of...@apache.org.
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 6560b6c2adf1e43e0e3d598426aaa261a96c44fb
Author: Oleh Fuks <ol...@gmail.com>
AuthorDate: Wed Jun 10 12:52:19 2020 +0300

    Added audit for computational resources
---
 .../epam/dlab/rest/contracts/ComputationalAPI.java |  1 +
 .../azure/ComputationalResourceAzure.java          |  2 +-
 .../dlab/backendapi/domain/AuditActionEnum.java    |  1 +
 .../resources/aws/ComputationalResourceAws.java    | 10 ++--
 .../azure/ComputationalResourceAzure.java          | 10 ++--
 .../resources/gcp/ComputationalResourceGcp.java    | 40 +++++++-------
 .../backendapi/service/ComputationalService.java   | 19 ++++---
 .../service/impl/ComputationalServiceImpl.java     | 45 ++++++++--------
 .../service/impl/EnvironmentServiceImpl.java       |  8 +--
 .../service/impl/SchedulerJobServiceImpl.java      | 14 ++---
 .../epam/dlab/backendapi/util/RequestBuilder.java  | 60 ++++++++++-----------
 .../resources/ExploratoryResourceTest.java         | 16 ------
 .../service/impl/ComputationalServiceImplTest.java | 63 ++++++++++++----------
 .../service/impl/EnvironmentServiceImplTest.java   |  7 +--
 .../service/impl/SchedulerJobServiceImplTest.java  | 43 +++++++--------
 15 files changed, 172 insertions(+), 167 deletions(-)

diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/ComputationalAPI.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/ComputationalAPI.java
index a909635..1586c0b 100644
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/ComputationalAPI.java
+++ b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/contracts/ComputationalAPI.java
@@ -20,6 +20,7 @@
 package com.epam.dlab.rest.contracts;
 
 public interface ComputationalAPI {
+	String AUDIT_MESSAGE = "Notebook name: %s";
 	String LIBRARY = "library/";
 	String COMPUTATIONAL = "computational";
 	String COMPUTATIONAL_CREATE = COMPUTATIONAL + "/create";
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java
index 59b5f27..2ca5c42 100644
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java
@@ -41,7 +41,7 @@ import javax.ws.rs.core.MediaType;
 @Consumes(MediaType.APPLICATION_JSON)
 @Produces(MediaType.APPLICATION_JSON)
 @Slf4j
-public class ComputationalResourceAzure {
+public class ComputationalResourceAzure implements ComputationalAPI {
 
 	@Inject
 	private SparkClusterService sparkClusterService;
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 eb49aa1..315925c 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
@@ -22,5 +22,6 @@ package com.epam.dlab.backendapi.domain;
 public enum AuditActionEnum {
     CREATE_PROJECT, START_PROJECT, STOP_PROJECT, TERMINATE_PROJECT, UPDATE_PROJECT,
     CREATE_NOTEBOOK, START_NOTEBOOK, STOP_NOTEBOOK, TERMINATE_NOTEBOOK, UPDATE_CLUSTER_CONFIG,
+    CREATE_DATA_ENGINE, CREATE_DATA_ENGINE_SERVICE, TERMINATE_COMPUTATIONAL,
     FOLLOW_NOTEBOOK_LINK
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ComputationalResourceAws.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ComputationalResourceAws.java
index 87f99bd..d6ab4f4 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ComputationalResourceAws.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ComputationalResourceAws.java
@@ -48,6 +48,7 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import java.util.Collections;
 import java.util.List;
 
 import static com.epam.dlab.dto.UserInstanceStatus.CREATING;
@@ -106,8 +107,8 @@ public class ComputationalResourceAws implements ComputationalAPI {
 					.config(form.getConfig())
 					.version(form.getVersion())
 					.build();
-			boolean resourceAdded = computationalService.createDataEngineService(userInfo, form,
-					awsComputationalResource, form.getProject());
+			boolean resourceAdded = computationalService.createDataEngineService(userInfo, form.getName(), form, awsComputationalResource,
+					form.getProject(), Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())));
 			return resourceAdded ? Response.ok().build() : Response.status(Response.Status.FOUND).build();
 		}
 
@@ -129,7 +130,7 @@ public class ComputationalResourceAws implements ComputationalAPI {
 		log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
 
 		validate(form);
-		return computationalService.createSparkCluster(userInfo, form, form.getProject())
+		return computationalService.createSparkCluster(userInfo, form.getName(), form, form.getProject(), Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())))
 				? Response.ok().build()
 				: Response.status(Response.Status.FOUND).build();
 	}
@@ -150,7 +151,8 @@ public class ComputationalResourceAws implements ComputationalAPI {
 							  @PathParam("computationalName") String computationalName) {
 		log.debug("Terminating computational resource {} for user {}", computationalName, userInfo.getName());
 
-		computationalService.terminateComputational(userInfo, projectName, exploratoryName, computationalName);
+		computationalService.terminateComputational(userInfo, userInfo.getName(), projectName, exploratoryName,
+				computationalName, Collections.singletonList(String.format(AUDIT_MESSAGE, exploratoryName)));
 
 		return Response.ok().build();
 	}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java
index ca18d14..922260b 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java
@@ -42,8 +42,11 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import java.util.Collections;
 import java.util.List;
 
+import static com.epam.dlab.rest.contracts.ComputationalAPI.AUDIT_MESSAGE;
+
 /**
  * Provides the REST API for the computational resource on Azure.
  */
@@ -79,16 +82,14 @@ public class ComputationalResourceAzure {
 	public Response createDataEngine(@Auth UserInfo userInfo,
 									 @Valid @NotNull SparkStandaloneClusterCreateForm form) {
 		log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
-
 		if (!UserRoles.checkAccess(userInfo, RoleType.COMPUTATIONAL, form.getImage(), userInfo.getRoles())) {
 			log.warn("Unauthorized attempt to create a {} by user {}", form.getImage(), userInfo.getName());
 			throw new DlabException("You do not have the privileges to create a " + form.getTemplateName());
 		}
 
-		return computationalService.createSparkCluster(userInfo, form, form.getProject())
+		return computationalService.createSparkCluster(userInfo, form.getName(), form, form.getProject(), Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())))
 				? Response.ok().build()
 				: Response.status(Response.Status.FOUND).build();
-
 	}
 
 	/**
@@ -108,7 +109,8 @@ public class ComputationalResourceAzure {
 
 		log.debug("Terminating computational resource {} for user {}", computationalName, userInfo.getName());
 
-		computationalService.terminateComputational(userInfo, projectName, exploratoryName, computationalName);
+		computationalService.terminateComputational(userInfo, userInfo.getName(), projectName, exploratoryName,
+				computationalName, Collections.singletonList(String.format(AUDIT_MESSAGE, exploratoryName)));
 
 		return Response.ok().build();
 	}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ComputationalResourceGcp.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ComputationalResourceGcp.java
index 087330a..71eaf35 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ComputationalResourceGcp.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ComputationalResourceGcp.java
@@ -48,6 +48,7 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import java.util.Collections;
 import java.util.List;
 
 import static com.epam.dlab.dto.UserInstanceStatus.CREATING;
@@ -82,7 +83,7 @@ public class ComputationalResourceGcp implements ComputationalAPI {
 	 * Asynchronously creates Dataproc cluster
 	 *
 	 * @param userInfo user info.
-	 * @param formDTO  DTO info about creation of the computational resource.
+	 * @param form     DTO info about creation of the computational resource.
 	 * @return 200 OK - if request success, 302 Found - for duplicates.
 	 * @throws IllegalArgumentException if docker image name is malformed
 	 */
@@ -90,30 +91,30 @@ public class ComputationalResourceGcp implements ComputationalAPI {
 	@Path("dataengine-service")
 	@Operation(tags = "computational", summary = "Create dataproc cluster")
 	public Response createDataEngineService(@Auth @Parameter(hidden = true) UserInfo userInfo,
-											@Valid @NotNull @Parameter GcpComputationalCreateForm formDTO) {
+											@Valid @NotNull @Parameter GcpComputationalCreateForm form) {
 
-		log.debug("Create computational resources for {} | form is {}", userInfo.getName(), formDTO);
+		log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
 
-		if (DataEngineType.CLOUD_SERVICE == DataEngineType.fromDockerImageName(formDTO.getImage())) {
-			validate(userInfo, formDTO);
+		if (DataEngineType.CLOUD_SERVICE == DataEngineType.fromDockerImageName(form.getImage())) {
+			validate(userInfo, form);
 			GcpComputationalResource gcpComputationalResource = GcpComputationalResource.builder().computationalName
-					(formDTO.getName())
-					.imageName(formDTO.getImage())
-					.templateName(formDTO.getTemplateName())
+					(form.getName())
+					.imageName(form.getImage())
+					.templateName(form.getTemplateName())
 					.status(CREATING.toString())
-					.masterShape(formDTO.getMasterInstanceType())
-					.slaveShape(formDTO.getSlaveInstanceType())
-					.slaveNumber(formDTO.getSlaveInstanceCount())
-					.masterNumber(formDTO.getMasterInstanceCount())
-					.preemptibleNumber(formDTO.getPreemptibleCount())
-					.version(formDTO.getVersion())
+					.masterShape(form.getMasterInstanceType())
+					.slaveShape(form.getSlaveInstanceType())
+					.slaveNumber(form.getSlaveInstanceCount())
+					.masterNumber(form.getMasterInstanceCount())
+					.preemptibleNumber(form.getPreemptibleCount())
+					.version(form.getVersion())
 					.build();
-			boolean resourceAdded = computationalService.createDataEngineService(userInfo, formDTO,
-					gcpComputationalResource, formDTO.getProject());
+			boolean resourceAdded = computationalService.createDataEngineService(userInfo, form.getName(), form, gcpComputationalResource,
+					form.getProject(), Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())));
 			return resourceAdded ? Response.ok().build() : Response.status(Response.Status.FOUND).build();
 		}
 
-		throw new IllegalArgumentException("Malformed image " + formDTO.getImage());
+		throw new IllegalArgumentException("Malformed image " + form.getImage());
 	}
 
 
@@ -135,7 +136,7 @@ public class ComputationalResourceGcp implements ComputationalAPI {
 			throw new DlabException("You do not have the privileges to create a " + form.getTemplateName());
 		}
 
-		return computationalService.createSparkCluster(userInfo, form, form.getProject())
+		return computationalService.createSparkCluster(userInfo, form.getName(), form, form.getProject(), Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())))
 				? Response.ok().build()
 				: Response.status(Response.Status.FOUND).build();
 	}
@@ -157,7 +158,8 @@ public class ComputationalResourceGcp implements ComputationalAPI {
 							  @PathParam("computationalName") String computationalName) {
 		log.debug("Terminating computational resource {} for user {}", computationalName, userInfo.getName());
 
-		computationalService.terminateComputational(userInfo, projectName, exploratoryName, computationalName);
+		computationalService.terminateComputational(userInfo, userInfo.getName(), projectName, exploratoryName,
+				computationalName, Collections.singletonList(String.format(AUDIT_MESSAGE, exploratoryName)));
 
 		return Response.ok().build();
 	}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ComputationalService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ComputationalService.java
index 4a6f392..135657f 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ComputationalService.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ComputationalService.java
@@ -35,27 +35,30 @@ public interface ComputationalService {
 	/**
 	 * Asynchronously triggers creation of Spark cluster
 	 *
-	 * @param userInfo user authentication info
-	 * @param form     input cluster parameters
+	 * @param userInfo     user authentication info
+	 * @param resourceName name of computational resource
+	 * @param form         input cluster parameters
+	 * @param auditInfo    additional info for audit
 	 * @return <code>true</code> if action is successfully triggered, <code>false</code>false if cluster with the same
 	 * name already exists
 	 * @throws IllegalArgumentException if input parameters exceed limits or docker image name is malformed
 	 */
-	boolean createSparkCluster(UserInfo userInfo, SparkStandaloneClusterCreateForm form, String project);
+	boolean createSparkCluster(UserInfo userInfo, String resourceName, SparkStandaloneClusterCreateForm form, String project, List<String> auditInfo);
 
 	/**
 	 * Asynchronously triggers termination of computational resources
 	 *
 	 * @param userInfo          user info of authenticated user
+	 * @param resourceCreator   username of resource creator
 	 * @param project           project name
-	 * @param exploratoryName   name of exploratory where to terminate computational resources with
-	 *                          <code>computationalName</code>
+	 * @param exploratoryName   name of exploratory where to terminate computational resources with <code>computationalName</code>
 	 * @param computationalName computational name
+	 * @param auditInfo         additional info for audit
 	 */
-	void terminateComputational(UserInfo userInfo, String project, String exploratoryName, String computationalName);
+	void terminateComputational(UserInfo userInfo, String resourceCreator, String project, String exploratoryName, String computationalName, List<String> auditInfo);
 
-	boolean createDataEngineService(UserInfo userInfo, ComputationalCreateFormDTO formDTO, UserComputationalResource
-			computationalResource, String project);
+	boolean createDataEngineService(UserInfo userInfo, String resourceName, ComputationalCreateFormDTO formDTO, UserComputationalResource
+			computationalResource, String project, List<String> auditInfo);
 
 	void stopSparkCluster(UserInfo userInfo, String project, String exploratoryName, String computationalName);
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java
index 722ee4d..d13fd6a 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java
@@ -21,8 +21,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.domain.EndpointDTO;
@@ -65,6 +69,9 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.CREATE_DATA_ENGINE;
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.CREATE_DATA_ENGINE_SERVICE;
+import static com.epam.dlab.backendapi.domain.AuditActionEnum.TERMINATE_COMPUTATIONAL;
 import static com.epam.dlab.dto.UserInstanceStatus.CREATING;
 import static com.epam.dlab.dto.UserInstanceStatus.FAILED;
 import static com.epam.dlab.dto.UserInstanceStatus.RECONFIGURING;
@@ -142,9 +149,10 @@ public class ComputationalServiceImpl implements ComputationalService {
 	}
 
 	@BudgetLimited
+	@Audit(action = CREATE_DATA_ENGINE)
 	@Override
-	public boolean createSparkCluster(UserInfo userInfo, SparkStandaloneClusterCreateForm form, @Project String project) {
-
+	public boolean createSparkCluster(@User UserInfo userInfo, @ResourceName String resourceName, SparkStandaloneClusterCreateForm form, @Project String project,
+									  @Info List<String> auditInfo) {
 		final ProjectDTO projectDTO = projectService.get(project);
 		final UserInstanceDTO instance =
 				exploratoryDAO.fetchExploratoryFields(userInfo.getName(), project, form.getNotebookName());
@@ -176,44 +184,39 @@ public class ComputationalServiceImpl implements ComputationalService {
 		}
 	}
 
+	@Audit(action = TERMINATE_COMPUTATIONAL)
 	@Override
-	public void terminateComputational(UserInfo userInfo, String project, String exploratoryName, String computationalName) {
+	public void terminateComputational(@User UserInfo userInfo, String resourceCreator, String project, String exploratoryName, @ResourceName String computationalName,
+									   @Info List<String> auditInfo) {
 		try {
+			updateComputationalStatus(resourceCreator, project, exploratoryName, computationalName, TERMINATING);
 
-			updateComputationalStatus(userInfo.getName(), project, exploratoryName, computationalName, TERMINATING);
-
-			final UserInstanceDTO userInstanceDTO = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), project,
-					exploratoryName);
-			UserComputationalResource compResource = computationalDAO.fetchComputationalFields(userInfo.getName(), project,
-					exploratoryName, computationalName);
+			final UserInstanceDTO userInstanceDTO = exploratoryDAO.fetchExploratoryFields(resourceCreator, project, exploratoryName);
+			UserComputationalResource compResource = computationalDAO.fetchComputationalFields(resourceCreator, project, exploratoryName, computationalName);
 
 			final DataEngineType dataEngineType = compResource.getDataEngineType();
 			EndpointDTO endpointDTO = endpointService.get(userInstanceDTO.getEndpoint());
-			ComputationalTerminateDTO dto = requestBuilder.newComputationalTerminate(userInfo, userInstanceDTO, compResource, endpointDTO);
+			ComputationalTerminateDTO dto = requestBuilder.newComputationalTerminate(resourceCreator, userInstanceDTO, compResource, endpointDTO);
 
 			final String provisioningUrl = Optional.ofNullable(DATA_ENGINE_TYPE_TERMINATE_URLS.get(dataEngineType))
 					.orElseThrow(UnsupportedOperationException::new);
-			String uuid =
-					provisioningService.post(endpointDTO.getUrl() + provisioningUrl,
-							userInfo.getAccessToken(), dto, String.class);
-			requestId.put(userInfo.getName(), uuid);
+			final String uuid = provisioningService.post(endpointDTO.getUrl() + provisioningUrl, userInfo.getAccessToken(), dto, String.class);
+			requestId.put(resourceCreator, uuid);
 		} catch (RuntimeException re) {
-
 			try {
-				updateComputationalStatus(userInfo.getName(), project, exploratoryName, computationalName, FAILED);
+				updateComputationalStatus(resourceCreator, project, exploratoryName, computationalName, FAILED);
 			} catch (DlabException e) {
-				log.error(COULD_NOT_UPDATE_THE_STATUS_MSG_FORMAT, computationalName, userInfo.getName(), e);
+				log.error(COULD_NOT_UPDATE_THE_STATUS_MSG_FORMAT, computationalName, resourceCreator, e);
 			}
-
 			throw re;
 		}
 	}
 
 	@BudgetLimited
+	@Audit(action = CREATE_DATA_ENGINE_SERVICE)
 	@Override
-	public boolean createDataEngineService(UserInfo userInfo, ComputationalCreateFormDTO formDTO,
-										   UserComputationalResource computationalResource, @Project String project) {
-
+	public boolean createDataEngineService(@User UserInfo userInfo, @ResourceName String resourceName, ComputationalCreateFormDTO formDTO,
+										   UserComputationalResource computationalResource, @Project String project, @Info List<String> auditInfo) {
 		final ProjectDTO projectDTO = projectService.get(project);
 		final UserInstanceDTO instance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), project, formDTO
 				.getNotebookName());
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 eb04e55..a396859 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
@@ -51,6 +51,7 @@ import java.util.stream.Stream;
 
 import static com.epam.dlab.backendapi.resources.dto.UserDTO.Status.ACTIVE;
 import static com.epam.dlab.backendapi.resources.dto.UserDTO.Status.NOT_ACTIVE;
+import static com.epam.dlab.rest.contracts.ComputationalAPI.AUDIT_MESSAGE;
 import static java.util.stream.Collectors.toList;
 
 @Singleton
@@ -161,10 +162,9 @@ public class EnvironmentServiceImpl implements EnvironmentService {
 
 	@ProjectAdmin
 	@Override
-	public void terminateComputational(@User UserInfo userInfo, String user, @Project String project,
-									   String exploratoryName, String computationalName) {
-		computationalService.terminateComputational(new UserInfo(user, userInfo.getAccessToken()), project, exploratoryName,
-				computationalName);
+	public void terminateComputational(@User UserInfo userInfo, String user, @Project String project, String exploratoryName, String computationalName) {
+		computationalService.terminateComputational(userInfo, user, project, exploratoryName, computationalName,
+				Collections.singletonList(String.format(AUDIT_MESSAGE, exploratoryName)));
 	}
 
 	private UserDTO toUserDTO(String u, UserDTO.Status status) {
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 e00a288..37deea6 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
@@ -223,13 +223,13 @@ public class SchedulerJobServiceImpl implements SchedulerJobService {
 	}
 
 	private void terminateComputational(SchedulerJobData job) {
-		final String user = job.getUser();
-		final String expName = job.getExploratoryName();
-		final String compName = job.getComputationalName();
-		final UserInfo userInfo = securityService.getServiceAccountInfo(user);
-		log.debug("Terminating exploratory {} computational {} for user {} by scheduler", expName, compName, user);
-		computationalService.terminateComputational(userInfo, job.getProject(), expName, compName);
-	}
+        final String user = job.getUser();
+        final String expName = job.getExploratoryName();
+        final String compName = job.getComputationalName();
+        final UserInfo userInfo = securityService.getServiceAccountInfo(user);
+        log.debug("Terminating exploratory {} computational {} for user {} by scheduler", expName, compName, user);
+        computationalService.terminateComputational(userInfo, user, job.getProject(), expName, compName, Collections.singletonList(AUDIT_MESSAGE));
+    }
 
 	private void stopExploratory(SchedulerJobData job) {
 		final String expName = job.getExploratoryName();
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 32bea28..a72db8d 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
@@ -444,36 +444,36 @@ public class RequestBuilder {
 	}
 
 	@SuppressWarnings("unchecked")
-	public <T extends ComputationalBase<T>> T newComputationalTerminate(UserInfo userInfo,
-																		UserInstanceDTO userInstanceDTO,
-																		UserComputationalResource computationalResource,
-																		EndpointDTO endpointDTO) {
-		T computationalTerminate;
-		CloudProvider cloudProvider = endpointDTO.getCloudProvider();
-		switch (cloudProvider) {
-			case AWS:
-				AwsComputationalTerminateDTO terminateDTO = newResourceSysBaseDTO(userInfo.getName(), cloudProvider,
-						AwsComputationalTerminateDTO.class);
-				if (computationalResource.getDataEngineType() == DataEngineType.CLOUD_SERVICE) {
-					terminateDTO.setClusterName(computationalResource.getComputationalId());
-				}
-				computationalTerminate = (T) terminateDTO;
-				break;
-			case AZURE:
-				computationalTerminate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ComputationalTerminateDTO.class);
-				break;
-			case GCP:
-				GcpComputationalTerminateDTO gcpTerminateDTO = newResourceSysBaseDTO(userInfo.getName(), cloudProvider,
-						GcpComputationalTerminateDTO.class);
-				if (computationalResource.getDataEngineType() == DataEngineType.CLOUD_SERVICE) {
-					gcpTerminateDTO.setClusterName(computationalResource.getComputationalId());
-				}
-				computationalTerminate = (T) gcpTerminateDTO;
-				break;
-
-			default:
-				throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
-		}
+    public <T extends ComputationalBase<T>> T newComputationalTerminate(String resourceCreator,
+                                                                        UserInstanceDTO userInstanceDTO,
+                                                                        UserComputationalResource computationalResource,
+                                                                        EndpointDTO endpointDTO) {
+        T computationalTerminate;
+        CloudProvider cloudProvider = endpointDTO.getCloudProvider();
+        switch (cloudProvider) {
+            case AWS:
+                AwsComputationalTerminateDTO terminateDTO = newResourceSysBaseDTO(resourceCreator, cloudProvider,
+                        AwsComputationalTerminateDTO.class);
+                if (computationalResource.getDataEngineType() == DataEngineType.CLOUD_SERVICE) {
+                    terminateDTO.setClusterName(computationalResource.getComputationalId());
+                }
+                computationalTerminate = (T) terminateDTO;
+                break;
+            case AZURE:
+                computationalTerminate = (T) newResourceSysBaseDTO(resourceCreator, cloudProvider, ComputationalTerminateDTO.class);
+                break;
+            case GCP:
+                GcpComputationalTerminateDTO gcpTerminateDTO = newResourceSysBaseDTO(resourceCreator, cloudProvider,
+                        GcpComputationalTerminateDTO.class);
+                if (computationalResource.getDataEngineType() == DataEngineType.CLOUD_SERVICE) {
+                    gcpTerminateDTO.setClusterName(computationalResource.getComputationalId());
+                }
+                computationalTerminate = (T) gcpTerminateDTO;
+                break;
+
+            default:
+                throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider);
+        }
 
 		return computationalTerminate
 				.withExploratoryName(userInstanceDTO.getExploratoryName())
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 a3e1dbd..a9ab5f2 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
@@ -144,22 +144,6 @@ public class ExploratoryResourceTest extends TestBase {
 	}
 
 	@Test
-	public void startWithFailedAuth() throws AuthenticationException {
-        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(), anyString(), anyList())).thenReturn("someUuid");
 		final Response response = resources.getJerseyTest()
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImplTest.java
index 74fc7f0..1238e51 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImplTest.java
@@ -70,6 +70,7 @@ import java.util.Optional;
 import static com.epam.dlab.dto.UserInstanceStatus.CREATING;
 import static com.epam.dlab.dto.UserInstanceStatus.RUNNING;
 import static com.epam.dlab.dto.UserInstanceStatus.STOPPED;
+import static com.epam.dlab.rest.contracts.ComputationalAPI.AUDIT_MESSAGE;
 import static java.util.Collections.singletonList;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -169,9 +170,9 @@ public class ComputationalServiceImplTest {
         when(provisioningService.post(anyString(), anyString(), any(ComputationalBase.class), any())).thenReturn(UUID);
         when(requestId.put(anyString(), anyString())).thenReturn(UUID);
 
-        SparkStandaloneClusterCreateForm sparkClusterCreateForm = (SparkStandaloneClusterCreateForm) formList.get(0);
-        boolean creationResult =
-                computationalService.createSparkCluster(userInfo, sparkClusterCreateForm, PROJECT);
+        SparkStandaloneClusterCreateForm form = (SparkStandaloneClusterCreateForm) formList.get(0);
+        boolean creationResult = computationalService.createSparkCluster(userInfo, form.getName(), form, PROJECT,
+                Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())));
         assertTrue(creationResult);
 
         verify(projectService).get(PROJECT);
@@ -179,7 +180,7 @@ public class ComputationalServiceImplTest {
 
         verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
         verify(requestBuilder).newComputationalCreate(
-                refEq(userInfo), refEq(projectDTO), refEq(userInstance), refEq(sparkClusterCreateForm), refEq(endpointDTO()));
+                refEq(userInfo), refEq(projectDTO), refEq(userInstance), refEq(form), refEq(endpointDTO()));
 
         verify(provisioningService)
                 .post(endpointDTO().getUrl() + ComputationalAPI.COMPUTATIONAL_CREATE_SPARK, TOKEN, compBaseMocked,
@@ -195,11 +196,10 @@ public class ComputationalServiceImplTest {
                 any(SparkStandaloneClusterResource.class))).thenReturn(false);
         when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString(), anyString())).thenReturn(userInstance);
 
-
-        boolean creationResult = computationalService.createSparkCluster(userInfo, (SparkStandaloneClusterCreateForm) formList.get(0),
-                PROJECT);
+        SparkStandaloneClusterCreateForm form = (SparkStandaloneClusterCreateForm) formList.get(0);
+        boolean creationResult = computationalService.createSparkCluster(userInfo, form.getName(), form, PROJECT,
+                Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())));
         assertFalse(creationResult);
-
         verify(computationalDAO).addComputational(eq(USER), eq(EXPLORATORY_NAME), eq(PROJECT), refEq(sparkClusterResource));
         verifyNoMoreInteractions(configuration, computationalDAO);
     }
@@ -214,9 +214,9 @@ public class ComputationalServiceImplTest {
         when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
                 .thenReturn(mock(UpdateResult.class));
 
-        SparkStandaloneClusterCreateForm sparkClusterCreateForm = (SparkStandaloneClusterCreateForm) formList.get(0);
+        SparkStandaloneClusterCreateForm form = (SparkStandaloneClusterCreateForm) formList.get(0);
         try {
-            computationalService.createSparkCluster(userInfo, sparkClusterCreateForm, PROJECT);
+            computationalService.createSparkCluster(userInfo, form.getName(), form, PROJECT, Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())));
         } catch (ResourceNotFoundException e) {
             assertEquals("Exploratory for user with name not found", e.getMessage());
         }
@@ -244,9 +244,9 @@ public class ComputationalServiceImplTest {
         when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
                 .thenReturn(mock(UpdateResult.class));
 
-        SparkStandaloneClusterCreateForm sparkClusterCreateForm = (SparkStandaloneClusterCreateForm) formList.get(0);
+        SparkStandaloneClusterCreateForm form = (SparkStandaloneClusterCreateForm) formList.get(0);
         try {
-            computationalService.createSparkCluster(userInfo, sparkClusterCreateForm, PROJECT);
+            computationalService.createSparkCluster(userInfo, form.getName(), form, PROJECT, Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())));
         } catch (DlabException e) {
             assertEquals("Cannot create instance of resource class ", e.getMessage());
         }
@@ -254,7 +254,7 @@ public class ComputationalServiceImplTest {
         verify(computationalDAO).addComputational(USER, EXPLORATORY_NAME, PROJECT, sparkClusterResource);
         verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
         verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
-        verify(requestBuilder).newComputationalCreate(userInfo, projectDTO, userInstance, sparkClusterCreateForm, endpointDTO());
+        verify(requestBuilder).newComputationalCreate(userInfo, projectDTO, userInstance, form, endpointDTO());
         verifyNoMoreInteractions(projectService, configuration, computationalDAO, exploratoryDAO, requestBuilder);
     }
 
@@ -276,19 +276,19 @@ public class ComputationalServiceImplTest {
         ComputationalTerminateDTO ctDto = new ComputationalTerminateDTO();
         ctDto.setComputationalName(COMP_NAME);
         ctDto.setExploratoryName(EXPLORATORY_NAME);
-        when(requestBuilder.newComputationalTerminate(any(UserInfo.class), any(UserInstanceDTO.class),
+        when(requestBuilder.newComputationalTerminate(anyString(), any(UserInstanceDTO.class),
                 any(UserComputationalResource.class), any(EndpointDTO.class))).thenReturn(ctDto);
 
         when(provisioningService.post(anyString(), anyString(), any(ComputationalTerminateDTO.class), any()))
                 .thenReturn(UUID);
         when(requestId.put(anyString(), anyString())).thenReturn(UUID);
 
-        computationalService.terminateComputational(userInfo, PROJECT, EXPLORATORY_NAME, COMP_NAME);
+        computationalService.terminateComputational(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, Collections.singletonList(AUDIT_MESSAGE));
 
         verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating, "self"));
         verify(computationalDAO).fetchComputationalFields(USER, PROJECT, EXPLORATORY_NAME, COMP_NAME);
 
-        verify(requestBuilder).newComputationalTerminate(userInfo, userInstance, ucResource, endpointDTO());
+        verify(requestBuilder).newComputationalTerminate(userInfo.getName(), userInstance, ucResource, endpointDTO());
 
         verify(provisioningService).post(endpointDTO().getUrl() + ComputationalAPI.COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC, TOKEN, ctDto,
                 String.class);
@@ -308,7 +308,7 @@ public class ComputationalServiceImplTest {
 				.thenReturn(mock(UpdateResult.class));
 
         try {
-            computationalService.terminateComputational(userInfo, PROJECT, EXPLORATORY_NAME, COMP_NAME);
+            computationalService.terminateComputational(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, Collections.singletonList(AUDIT_MESSAGE));
         } catch (DlabException e) {
             assertEquals("Could not update computational resource status", e.getMessage());
         }
@@ -329,7 +329,7 @@ public class ComputationalServiceImplTest {
                 .thenReturn(mock(UpdateResult.class));
 
         try {
-            computationalService.terminateComputational(userInfo, PROJECT, EXPLORATORY_NAME, COMP_NAME);
+            computationalService.terminateComputational(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, Collections.singletonList(AUDIT_MESSAGE));
         } catch (DlabException e) {
             assertEquals("Computational resource for user with exploratory name not found.", e.getMessage());
         }
@@ -356,14 +356,14 @@ public class ComputationalServiceImplTest {
         when(computationalDAO.fetchComputationalFields(anyString(), anyString(), anyString(), anyString())).thenReturn(ucResource);
 
         doThrow(new DlabException("Cannot create instance of resource class "))
-                .when(requestBuilder).newComputationalTerminate(any(UserInfo.class), any(UserInstanceDTO.class),
+                .when(requestBuilder).newComputationalTerminate(anyString(), any(UserInstanceDTO.class),
                 any(UserComputationalResource.class), any(EndpointDTO.class));
 
         when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
                 .thenReturn(mock(UpdateResult.class));
 
         try {
-            computationalService.terminateComputational(userInfo, PROJECT, EXPLORATORY_NAME, COMP_NAME);
+            computationalService.terminateComputational(userInfo, userInfo.getName(), PROJECT, EXPLORATORY_NAME, COMP_NAME, Collections.singletonList(AUDIT_MESSAGE));
         } catch (DlabException e) {
             assertEquals("Cannot create instance of resource class ", e.getMessage());
         }
@@ -373,7 +373,7 @@ public class ComputationalServiceImplTest {
 
         verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
 
-        verify(requestBuilder).newComputationalTerminate(userInfo, userInstance, ucResource, endpointDTO());
+        verify(requestBuilder).newComputationalTerminate(userInfo.getName(), userInstance, ucResource, endpointDTO());
         verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
         verifyNoMoreInteractions(computationalDAO, exploratoryDAO, requestBuilder);
     }
@@ -395,8 +395,9 @@ public class ComputationalServiceImplTest {
         when(provisioningService.post(anyString(), anyString(), any(ComputationalBase.class), any())).thenReturn(UUID);
         when(requestId.put(anyString(), anyString())).thenReturn(UUID);
 
-        boolean creationResult =
-                computationalService.createDataEngineService(userInfo, formList.get(1), ucResource, PROJECT);
+        ComputationalCreateFormDTO form = formList.get(1);
+        boolean creationResult = computationalService.createDataEngineService(userInfo, form.getName(), form, ucResource, PROJECT,
+                Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())));
         assertTrue(creationResult);
 
         verify(projectService).get(PROJECT);
@@ -422,8 +423,9 @@ public class ComputationalServiceImplTest {
         when(computationalDAO.addComputational(anyString(), anyString(), any(), any(UserComputationalResource.class)))
                 .thenReturn(false);
 
-        boolean creationResult = computationalService.createDataEngineService(userInfo, formList.get(1), ucResource,
-                PROJECT);
+        ComputationalCreateFormDTO form = formList.get(1);
+        boolean creationResult = computationalService.createDataEngineService(userInfo, form.getName(), form, ucResource, PROJECT,
+                Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())));
         assertFalse(creationResult);
 
         verify(computationalDAO).addComputational(eq(USER), eq(EXPLORATORY_NAME), eq(PROJECT), refEq(ucResource));
@@ -440,8 +442,10 @@ public class ComputationalServiceImplTest {
         when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
                 .thenReturn(mock(UpdateResult.class));
 
+        ComputationalCreateFormDTO form = formList.get(1);
         try {
-            computationalService.createDataEngineService(userInfo, formList.get(1), ucResource, PROJECT);
+            computationalService.createDataEngineService(userInfo, form.getName(), form, ucResource, PROJECT,
+                    Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())));
         } catch (DlabException e) {
             assertEquals("Exploratory for user with name not found", e.getMessage());
         }
@@ -472,9 +476,10 @@ public class ComputationalServiceImplTest {
         when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
                 .thenReturn(mock(UpdateResult.class));
 
-        ComputationalCreateFormDTO computationalCreateFormDTO = formList.get(1);
+        ComputationalCreateFormDTO form = formList.get(1);
         try {
-            computationalService.createDataEngineService(userInfo, computationalCreateFormDTO, ucResource, PROJECT);
+            computationalService.createDataEngineService(userInfo, form.getName(), form, ucResource, PROJECT,
+                    Collections.singletonList(String.format(AUDIT_MESSAGE, form.getNotebookName())));
         } catch (DlabException e) {
             assertEquals("Could not send request for creation the computational resource compName: " +
                     "Cannot create instance of resource class ", e.getMessage());
@@ -484,7 +489,7 @@ public class ComputationalServiceImplTest {
         verify(computationalDAO).addComputational(eq(USER), eq(EXPLORATORY_NAME), eq(PROJECT), refEq(ucResource));
         verify(exploratoryDAO).fetchExploratoryFields(USER, PROJECT, EXPLORATORY_NAME);
         verify(requestBuilder).newComputationalCreate(
-                refEq(userInfo), refEq(projectDTO), refEq(userInstance), refEq(computationalCreateFormDTO), refEq(endpointDTO()));
+                refEq(userInfo), refEq(projectDTO), refEq(userInstance), refEq(form), refEq(endpointDTO()));
         verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
 
         verifyNoMoreInteractions(projectService, computationalDAO, exploratoryDAO, requestBuilder);
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 7bde7a6..ce80c08 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
@@ -65,6 +65,7 @@ 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 AUDIT_MESSAGE = "Notebook name: %s";
 	private static final String DLAB_SYSTEM_USER = "DLab system user";
 	private static final String USER = "test";
 	private static final String EXPLORATORY_NAME_1 = "expName1";
@@ -187,12 +188,12 @@ public class EnvironmentServiceImplTest {
 	public void terminateComputational() {
 		final UserInfo userInfo = getUserInfo();
 		doNothing().when(computationalService)
-				.terminateComputational(any(UserInfo.class), anyString(), anyString(), anyString());
+				.terminateComputational(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyList());
 
 		environmentService.terminateComputational(userInfo, USER, PROJECT_NAME, EXPLORATORY_NAME_1, "compName");
 
-		verify(computationalService)
-				.terminateComputational(refEq(userInfo), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq("compName"));
+		verify(computationalService).terminateComputational(refEq(userInfo), eq(userInfo.getName()), eq(PROJECT_NAME), eq(EXPLORATORY_NAME_1), eq("compName"),
+				eq(Collections.singletonList(String.format(AUDIT_MESSAGE, EXPLORATORY_NAME_1))));
 		verifyNoMoreInteractions(securityService, computationalService);
 	}
 
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 2b535fe..5b9b738 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
@@ -866,27 +866,28 @@ public class SchedulerJobServiceImplTest {
 
 	@Test
 	public void testTerminateComputationalByScheduler() {
-		final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
-		final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
-		final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
-				LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
-		final LocalDate finishDate = LocalDate.now().plusDays(1);
-		final SchedulerJobData schedulerJobData = getSchedulerJobData(LocalDate.now(), finishDate, startDays, stopDays
-				, terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
-		);
-		when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
-				anyVararg())).thenReturn(singletonList(schedulerJobData));
-		when(securityService.getServiceAccountInfo(anyString())).thenReturn(getUserInfo());
-
-		schedulerJobService.terminateComputationalByScheduler();
-
-		verify(securityService).getServiceAccountInfo(USER);
-		verify(schedulerJobDAO)
-				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, STOPPED, RUNNING);
-		verify(computationalService).terminateComputational(refEq(getUserInfo()), eq(PROJECT),
-				eq(EXPLORATORY_NAME), eq(COMPUTATIONAL_NAME));
-		verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
-	}
+        final List<DayOfWeek> stopDays = Arrays.asList(DayOfWeek.values());
+        final List<DayOfWeek> startDays = Arrays.asList(DayOfWeek.values());
+        final LocalDateTime terminateDateTime = LocalDateTime.of(LocalDate.now(),
+                LocalTime.now().truncatedTo(ChronoUnit.MINUTES));
+        final LocalDate finishDate = LocalDate.now().plusDays(1);
+        final SchedulerJobData schedulerJobData = getSchedulerJobData(LocalDate.now(), finishDate, startDays, stopDays
+                , terminateDateTime, false, USER, LocalTime.now().truncatedTo(ChronoUnit.MINUTES)
+        );
+        when(schedulerJobDAO.getComputationalSchedulerDataWithOneOfStatus(any(UserInstanceStatus.class),
+                anyVararg())).thenReturn(singletonList(schedulerJobData));
+        UserInfo userInfo = getUserInfo();
+        when(securityService.getServiceAccountInfo(anyString())).thenReturn(userInfo);
+
+        schedulerJobService.terminateComputationalByScheduler();
+
+        verify(securityService).getServiceAccountInfo(USER);
+        verify(schedulerJobDAO)
+                .getComputationalSchedulerDataWithOneOfStatus(RUNNING, STOPPED, RUNNING);
+        verify(computationalService).terminateComputational(refEq(userInfo), eq(userInfo.getName()), eq(PROJECT), eq(EXPLORATORY_NAME), eq(COMPUTATIONAL_NAME),
+                eq(Collections.singletonList(AUDIT_MESSAGE)));
+        verifyNoMoreInteractions(securityService, schedulerJobDAO, computationalService);
+    }
 
 	@Test
 	public void testTerminateComputationalBySchedulerWhenSchedulerIsNotConfigured() {


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


[incubator-dlab] 06/07: Merge remote-tracking branch 'origin/audit' into audit

Posted by of...@apache.org.
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 66f49da46d5844003b11cae500b128a99e6ca31a
Merge: 8032353 e6d4e5d
Author: Oleh Fuks <ol...@gmail.com>
AuthorDate: Wed Jun 10 12:11:52 2020 +0300

    Merge remote-tracking branch 'origin/audit' into audit

 .../templates/proxy_location_webapp_template.conf  |   2 +-
 .../src/ssn/templates/ssn.yml                      |   2 +-
 pom.xml                                            |   1 +
 ...BucketDownloadDTO.java => BucketDeleteDTO.java} |   9 +-
 services/provisioning-service/pom.xml              |  22 +-
 .../dlab/backendapi/resources/BucketResource.java  |  74 ++-
 .../dlab/backendapi/service/BucketService.java     |   9 +-
 .../service/impl/aws/BucketServiceAwsImpl.java     |  51 +-
 .../service/impl/azure/BucketServiceAzureImpl.java |  73 ++-
 .../service/impl/gcp/BucketServiceGcpImpl.java     |  37 +-
 services/self-service/pom.xml                      |  10 +
 services/self-service/self-service.yml             |   2 +-
 .../epam/dlab/backendapi/dao/ExploratoryDAO.java   |   4 +-
 .../epam/dlab/backendapi/dao/UserRoleDaoImpl.java  |  20 +-
 .../dlab/backendapi/resources/BucketResource.java  |  82 ++-
 .../backendapi/resources/ExploratoryResource.java  |   3 -
 .../azure/ComputationalResourceAzure.java          |   3 -
 .../backendapi/resources/dto/BucketDeleteDTO.java} |  11 +-
 .../backendapi/resources/dto/UserResourceInfo.java |  70 +--
 .../dlab/backendapi/resources/dto/UserRoleDto.java |   8 +
 .../dlab/backendapi/service/BucketService.java     |   7 +-
 .../backendapi/service/impl/BucketServiceImpl.java |  43 +-
 .../service/impl/EndpointServiceImpl.java          |   6 +-
 .../service/impl/EnvironmentServiceImpl.java       |  29 +-
 .../impl/InfrastructureInfoServiceImpl.java        |  60 +--
 .../impl/InfrastructureTemplateServiceImpl.java    |  35 +-
 .../src/main/resources/mongo/aws/mongo_roles.json  |   8 +-
 .../main/resources/mongo/azure/mongo_roles.json    |   8 +-
 .../src/main/resources/mongo/gcp/mongo_roles.json  |   8 +-
 .../manage-environment-dilog.component.html        |   2 +-
 .../manage-environment-dilog.component.ts          |   4 +
 .../management-grid/management-grid.component.html |   5 +-
 .../management-grid/management-grid.component.scss |   5 +-
 .../management-grid/management-grid.component.ts   |  31 +-
 .../administration/management/management.model.ts  |   6 +-
 .../main/resources/webapp/src/app/app.module.ts    |  10 +-
 .../resources/webapp/src/app/app.routing.module.ts |  12 +-
 .../convert-file-size/convert-file-size.pipe.ts}   |  36 +-
 .../src/app/core/pipes/convert-file-size/index.ts} |  21 +-
 .../src/app/core/services/appRouting.service.ts    |   1 -
 .../services/applicationServiceFacade.service.ts   |  24 +-
 .../webapp/src/app/core/services/audit.service.ts  |  44 ++
 .../app/core/services/bucket-browser.service.ts    |   6 +-
 .../webapp/src/app/core/util/copyPathUtils.ts}     |  27 +-
 .../resources/webapp/src/app/core/util/patterns.ts |   1 +
 .../webapp/src/app/core/util/sortUtils.ts          |   8 +-
 .../audit/audit-grid/audit-grid.component.html     | 147 ++++++
 .../audit/audit-grid/audit-grid.component.scss     | 237 +++++++++
 .../audit/audit-grid/audit-grid.component.ts       | 135 +++++
 .../audit-toolbar/audit-toolbar.component.html}    |  10 +-
 .../audit-toolbar/audit-toolbar.component.scss}    |   0
 .../audit-toolbar/audit-toolbar.component.ts}      |  34 +-
 .../src/app/reports/audit/audit.component.ts       |  99 ++++
 .../audit/audit.module.ts}                         |  26 +-
 .../src/app/reports/audit/filter-audit.model.ts    |  25 +
 .../reporting-grid/reporting-grid.component.html   |   2 +-
 .../reporting-grid/reporting-grid.component.scss   |   0
 .../reporting-grid/reporting-grid.component.ts     |  12 +-
 .../{ => reports}/reporting/reporting.component.ts |   9 +-
 .../{ => reports}/reporting/reporting.module.ts    |   6 +-
 .../reporting/toolbar/toolbar.component.html       |   8 +-
 .../reporting/toolbar/toolbar.component.scss       |   0
 .../reporting/toolbar/toolbar.component.ts         |  10 +-
 .../webapp/src/app/reports/reports.module.ts}      |  22 +-
 .../bucket-browser/bucket-browser.component.html   | 285 ++++++++---
 .../bucket-browser/bucket-browser.component.scss   | 556 +++++++++++++++++++--
 .../bucket-browser/bucket-browser.component.ts     | 395 ++++++++++++---
 .../bucket-browser.module.ts}                      |  35 +-
 .../bucket-confirmation-dialog.component.html      | 122 +++++
 .../bucket-confirmation-dialog.component.scss      | 176 +++++++
 .../bucket-confirmation-dialog.component.ts        |  58 +++
 .../bucket-browser/bucket-data.service.ts          |  87 +++-
 .../buckets-tree/bucket-tree.component.html        |  25 +
 .../buckets-tree/bucket-tree.component.scss        | 106 ++++
 .../buckets-tree/bucket-tree.component.ts          | 101 ++++
 .../folder-tree/folder-tree.component.html         |  75 ++-
 .../folder-tree/folder-tree.component.scss         |  69 ++-
 .../folder-tree/folder-tree.component.ts           | 203 ++++----
 .../cluster-details/cluster-details.component.html |   2 +-
 .../cluster-details/cluster-details.component.ts   |  11 +-
 .../cost-details-dialog.component.html             |   4 +-
 .../detail-dialog/detail-dialog.component.html     | 154 ++++--
 .../detail-dialog/detail-dialog.component.scss     |  19 +-
 .../detail-dialog/detail-dialog.component.ts       |  40 +-
 .../install-libraries.component.ts                 |  10 +-
 .../resources-grid/resources-grid.component.ts     |  40 +-
 .../resources-grid/resources-grid.model.ts         |   4 +
 .../src/app/resources/resources.component.html     |  24 +-
 .../src/app/resources/resources.component.ts       |  18 +-
 .../webapp/src/app/resources/resources.module.ts   |  30 +-
 .../multi-level-select-dropdown.component.ts       |   2 +-
 .../webapp/src/app/shared/material.module.ts       |   3 +-
 .../src/app/shared/navbar/navbar.component.html    |  50 +-
 .../src/assets/img/blank-file-svgrepo-com.svg      |  41 ++
 .../webapp/src/assets/styles/_dialogs.scss         |  62 +++
 .../src/main/resources/webapp/src/styles.scss      |  14 +-
 96 files changed, 3688 insertions(+), 855 deletions(-)



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


[incubator-dlab] 03/07: Added audit endpoint

Posted by of...@apache.org.
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 b4291eeb99b50c41a033dab56a50c7273aeaa551
Author: Oleh Fuks <ol...@gmail.com>
AuthorDate: Tue Jun 9 12:08:42 2020 +0300

    Added audit endpoint
---
 .../dlab/backendapi/SelfServiceApplication.java    | 39 ++++++++++++++++++++--
 .../com/epam/dlab/backendapi/dao/AuditDAO.java     |  4 +--
 .../com/epam/dlab/backendapi/dao/AuditDAOImpl.java |  4 +--
 .../dlab/backendapi/domain/AuditActionEnum.java    |  3 +-
 .../dlab/backendapi/domain/AuditCreateDTO.java     | 10 +++---
 .../com/epam/dlab/backendapi/domain/AuditDTO.java  |  6 ++--
 .../backendapi/interceptor/AuditInterceptor.java   |  4 +--
 .../AuditResource.java}                            | 29 +++++++++++-----
 .../epam/dlab/backendapi/service/AuditService.java |  5 ++-
 .../backendapi/service/impl/AuditServiceImpl.java  | 16 ++++++++-
 10 files changed, 93 insertions(+), 27 deletions(-)

diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java
index 6a12ea5..beaf917 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java
@@ -27,8 +27,34 @@ import com.epam.dlab.backendapi.dropwizard.listeners.MongoStartupListener;
 import com.epam.dlab.backendapi.dropwizard.listeners.RestoreHandlerStartupListener;
 import com.epam.dlab.backendapi.healthcheck.MongoHealthCheck;
 import com.epam.dlab.backendapi.modules.ModuleFactory;
-import com.epam.dlab.backendapi.resources.*;
-import com.epam.dlab.backendapi.resources.callback.*;
+import com.epam.dlab.backendapi.resources.ApplicationSettingResource;
+import com.epam.dlab.backendapi.resources.AuditResource;
+import com.epam.dlab.backendapi.resources.BackupResource;
+import com.epam.dlab.backendapi.resources.EndpointResource;
+import com.epam.dlab.backendapi.resources.EnvironmentResource;
+import com.epam.dlab.backendapi.resources.ExploratoryResource;
+import com.epam.dlab.backendapi.resources.GitCredsResource;
+import com.epam.dlab.backendapi.resources.ImageExploratoryResource;
+import com.epam.dlab.backendapi.resources.InfrastructureInfoResource;
+import com.epam.dlab.backendapi.resources.InfrastructureTemplateResource;
+import com.epam.dlab.backendapi.resources.KeycloakResource;
+import com.epam.dlab.backendapi.resources.LibExploratoryResource;
+import com.epam.dlab.backendapi.resources.ProjectResource;
+import com.epam.dlab.backendapi.resources.SchedulerJobResource;
+import com.epam.dlab.backendapi.resources.SystemInfoResource;
+import com.epam.dlab.backendapi.resources.UserGroupResource;
+import com.epam.dlab.backendapi.resources.UserRoleResource;
+import com.epam.dlab.backendapi.resources.UserSettingsResource;
+import com.epam.dlab.backendapi.resources.callback.BackupCallback;
+import com.epam.dlab.backendapi.resources.callback.CheckInactivityCallback;
+import com.epam.dlab.backendapi.resources.callback.ComputationalCallback;
+import com.epam.dlab.backendapi.resources.callback.EnvironmentStatusCallback;
+import com.epam.dlab.backendapi.resources.callback.ExploratoryCallback;
+import com.epam.dlab.backendapi.resources.callback.GitCredsCallback;
+import com.epam.dlab.backendapi.resources.callback.ImageCallback;
+import com.epam.dlab.backendapi.resources.callback.LibraryCallback;
+import com.epam.dlab.backendapi.resources.callback.ProjectCallback;
+import com.epam.dlab.backendapi.resources.callback.ReuploadKeyCallback;
 import com.epam.dlab.backendapi.schedulers.internal.ManagedScheduler;
 import com.epam.dlab.backendapi.service.EndpointService;
 import com.epam.dlab.backendapi.servlet.guacamole.GuacamoleServlet;
@@ -37,7 +63,13 @@ import com.epam.dlab.constants.ServiceConsts;
 import com.epam.dlab.migration.mongo.DlabMongoMigration;
 import com.epam.dlab.mongo.MongoServiceFactory;
 import com.epam.dlab.rest.client.RESTService;
-import com.epam.dlab.rest.mappers.*;
+import com.epam.dlab.rest.mappers.DlabValidationExceptionMapper;
+import com.epam.dlab.rest.mappers.JsonProcessingExceptionMapper;
+import com.epam.dlab.rest.mappers.ResourceConflictExceptionMapper;
+import com.epam.dlab.rest.mappers.ResourceNotFoundExceptionMapper;
+import com.epam.dlab.rest.mappers.ResourceQuoteReachedExceptionMapper;
+import com.epam.dlab.rest.mappers.RuntimeExceptionMapper;
+import com.epam.dlab.rest.mappers.ValidationExceptionMapper;
 import com.epam.dlab.util.ServiceUtils;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
@@ -160,6 +192,7 @@ public class SelfServiceApplication extends Application<SelfServiceApplicationCo
 		jersey.register(injector.getInstance(KeycloakResource.class));
 		jersey.register(injector.getInstance(EndpointResource.class));
 		jersey.register(injector.getInstance(ProjectResource.class));
+		jersey.register(injector.getInstance(AuditResource.class));
 		jersey.register(injector.getInstance(ProjectCallback.class));
 	}
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java
index b9a7727..d757758 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java
@@ -19,8 +19,8 @@
 
 package com.epam.dlab.backendapi.dao;
 
-import com.epam.dlab.backendapi.domain.AuditCreateDTO;
+import com.epam.dlab.backendapi.domain.AuditDTO;
 
 public interface AuditDAO {
-    void save(AuditCreateDTO audit);
+    void save(AuditDTO audit);
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java
index 2de30aa..987d947 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java
@@ -19,13 +19,13 @@
 
 package com.epam.dlab.backendapi.dao;
 
-import com.epam.dlab.backendapi.domain.AuditCreateDTO;
+import com.epam.dlab.backendapi.domain.AuditDTO;
 
 public class AuditDAOImpl extends BaseDAO implements AuditDAO {
     private final static String AUDIT_COLLECTION = "audit";
 
     @Override
-    public void save(AuditCreateDTO audit) {
+    public void save(AuditDTO audit) {
         insertOne(AUDIT_COLLECTION, audit);
     }
 }
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 431e0c7..eb49aa1 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
@@ -21,5 +21,6 @@ package com.epam.dlab.backendapi.domain;
 
 public enum AuditActionEnum {
     CREATE_PROJECT, START_PROJECT, STOP_PROJECT, TERMINATE_PROJECT, UPDATE_PROJECT,
-    CREATE_NOTEBOOK, START_NOTEBOOK, STOP_NOTEBOOK, TERMINATE_NOTEBOOK, UPDATE_CLUSTER_CONFIG
+    CREATE_NOTEBOOK, START_NOTEBOOK, STOP_NOTEBOOK, TERMINATE_NOTEBOOK, UPDATE_CLUSTER_CONFIG,
+    FOLLOW_NOTEBOOK_LINK
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditCreateDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditCreateDTO.java
index de40808..b99b909 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditCreateDTO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditCreateDTO.java
@@ -19,17 +19,19 @@
 
 package com.epam.dlab.backendapi.domain;
 
-import lombok.Builder;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
 
 import java.util.List;
 
 
 @Data
-@Builder
+@JsonIgnoreProperties(ignoreUnknown = true)
 public class AuditCreateDTO {
-    private final String user;
-    private final AuditActionEnum action;
+    @NotBlank(message = "field cannot be empty")
+    @JsonProperty("resource_name")
     private final String resourceName;
     private final List<String> info;
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java
index 2a337e5..6eb6acf 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java
@@ -19,14 +19,16 @@
 
 package com.epam.dlab.backendapi.domain;
 
+import lombok.Builder;
 import lombok.Data;
 
-import java.util.Date;
+import java.util.List;
 
 @Data
+@Builder
 public class AuditDTO {
     private final String user;
     private final AuditActionEnum action;
     private final String resourceName;
-    private final Date date;
+    private final List<String> info;
 }
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 713e587..7e1011b 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
@@ -25,7 +25,7 @@ import com.epam.dlab.backendapi.annotation.Info;
 import com.epam.dlab.backendapi.annotation.ResourceName;
 import com.epam.dlab.backendapi.annotation.User;
 import com.epam.dlab.backendapi.domain.AuditActionEnum;
-import com.epam.dlab.backendapi.domain.AuditCreateDTO;
+import com.epam.dlab.backendapi.domain.AuditDTO;
 import com.epam.dlab.backendapi.service.AuditService;
 import com.epam.dlab.exceptions.DlabException;
 import com.google.inject.Inject;
@@ -55,7 +55,7 @@ public class AuditInterceptor implements MethodInterceptor {
         final String resourceName = getResourceName(mi, parameters);
         final List<String> infoMap = getInfo(mi, parameters);
 
-        AuditCreateDTO auditCreateDTO = AuditCreateDTO.builder()
+        AuditDTO auditCreateDTO = AuditDTO.builder()
                 .user(user)
                 .action(action)
                 .resourceName(resourceName)
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/AuditResource.java
similarity index 57%
copy from services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java
copy to services/self-service/src/main/java/com/epam/dlab/backendapi/resources/AuditResource.java
index d73460b..f6a2004 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/AuditResource.java
@@ -17,23 +17,34 @@
  * under the License.
  */
 
-package com.epam.dlab.backendapi.service.impl;
+package com.epam.dlab.backendapi.resources;
 
-import com.epam.dlab.backendapi.dao.AuditDAO;
+import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.domain.AuditCreateDTO;
 import com.epam.dlab.backendapi.service.AuditService;
 import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
 
-public class AuditServiceImpl implements AuditService {
-    private final AuditDAO auditDAO;
+import javax.validation.Valid;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("/audit")
+public class AuditResource {
+    private final AuditService auditService;
 
     @Inject
-    public AuditServiceImpl(AuditDAO auditDAO) {
-        this.auditDAO = auditDAO;
+    public AuditResource(AuditService auditService) {
+        this.auditService = auditService;
     }
 
-    @Override
-    public void save(AuditCreateDTO audit) {
-        auditDAO.save(audit);
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response createEndpoint(@Auth UserInfo userInfo, @Valid AuditCreateDTO auditCreateDTO) {
+        auditService.save(userInfo.getName(), auditCreateDTO);
+        return Response.ok().build();
     }
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java
index b7f4fce..785c59b 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java
@@ -20,7 +20,10 @@
 package com.epam.dlab.backendapi.service;
 
 import com.epam.dlab.backendapi.domain.AuditCreateDTO;
+import com.epam.dlab.backendapi.domain.AuditDTO;
 
 public interface AuditService {
-    void save(AuditCreateDTO audit);
+    void save(AuditDTO audit);
+
+    void save(String user, AuditCreateDTO audit);
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java
index d73460b..d35e00f 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java
@@ -20,7 +20,9 @@
 package com.epam.dlab.backendapi.service.impl;
 
 import com.epam.dlab.backendapi.dao.AuditDAO;
+import com.epam.dlab.backendapi.domain.AuditActionEnum;
 import com.epam.dlab.backendapi.domain.AuditCreateDTO;
+import com.epam.dlab.backendapi.domain.AuditDTO;
 import com.epam.dlab.backendapi.service.AuditService;
 import com.google.inject.Inject;
 
@@ -33,7 +35,19 @@ public class AuditServiceImpl implements AuditService {
     }
 
     @Override
-    public void save(AuditCreateDTO audit) {
+    public void save(AuditDTO audit) {
         auditDAO.save(audit);
     }
+
+    @Override
+    public void save(String user, AuditCreateDTO audit) {
+        AuditDTO auditDTO = AuditDTO.builder()
+                .user(user)
+                .resourceName(audit.getResourceName())
+                .action(AuditActionEnum.FOLLOW_NOTEBOOK_LINK)
+                .info(audit.getInfo())
+                .build();
+
+        auditDAO.save(auditDTO);
+    }
 }


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


[incubator-dlab] 05/07: Merge remote-tracking branch 'origin/audit' into audit

Posted by of...@apache.org.
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 80323538fd8fb806a2a0dc1b0610379b2dde52a5
Merge: 2c5c0f7 28ed0cb
Author: Oleh Fuks <ol...@gmail.com>
AuthorDate: Tue Jun 9 14:34:05 2020 +0300

    Merge remote-tracking branch 'origin/audit' into audit
    
    # Conflicts:
    #	services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java
    #	services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java
    #	services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditActionEnum.java
    #	services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditCreateDTO.java
    #	services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java
    #	services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/AuditInterceptor.java
    #	services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java
    #	services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java
    #	services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java



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


[incubator-dlab] 04/07: Added endpoint to retrieve audit

Posted by of...@apache.org.
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 2c5c0f7419d3035b92c9531ec35e28a3245c1434
Author: Oleh Fuks <ol...@gmail.com>
AuthorDate: Tue Jun 9 14:17:53 2020 +0300

    Added endpoint to retrieve audit
---
 .../src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java   |  4 ++++
 .../main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java   |  7 +++++++
 .../main/java/com/epam/dlab/backendapi/domain/AuditDTO.java    |  4 ++++
 .../java/com/epam/dlab/backendapi/resources/AuditResource.java | 10 +++++++++-
 .../java/com/epam/dlab/backendapi/service/AuditService.java    |  4 ++++
 .../epam/dlab/backendapi/service/impl/AuditServiceImpl.java    |  7 +++++++
 6 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java
index d757758..3c9d825 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAO.java
@@ -21,6 +21,10 @@ package com.epam.dlab.backendapi.dao;
 
 import com.epam.dlab.backendapi.domain.AuditDTO;
 
+import java.util.List;
+
 public interface AuditDAO {
     void save(AuditDTO audit);
+
+    List<AuditDTO> getAudit();
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java
index 987d947..234011f 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/AuditDAOImpl.java
@@ -21,6 +21,8 @@ package com.epam.dlab.backendapi.dao;
 
 import com.epam.dlab.backendapi.domain.AuditDTO;
 
+import java.util.List;
+
 public class AuditDAOImpl extends BaseDAO implements AuditDAO {
     private final static String AUDIT_COLLECTION = "audit";
 
@@ -28,4 +30,9 @@ public class AuditDAOImpl extends BaseDAO implements AuditDAO {
     public void save(AuditDTO audit) {
         insertOne(AUDIT_COLLECTION, audit);
     }
+
+    @Override
+    public List<AuditDTO> getAudit() {
+        return find(AUDIT_COLLECTION, AuditDTO.class);
+    }
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java
index 6eb6acf..5af65cd 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/AuditDTO.java
@@ -19,16 +19,20 @@
 
 package com.epam.dlab.backendapi.domain;
 
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import lombok.Builder;
 import lombok.Data;
 
+import java.util.Date;
 import java.util.List;
 
 @Data
 @Builder
+@JsonIgnoreProperties(ignoreUnknown = true)
 public class AuditDTO {
     private final String user;
     private final AuditActionEnum action;
     private final String resourceName;
     private final List<String> info;
+    private Date timestamp;
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/AuditResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/AuditResource.java
index f6a2004..3dccb90 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/AuditResource.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/AuditResource.java
@@ -27,8 +27,10 @@ import io.dropwizard.auth.Auth;
 
 import javax.validation.Valid;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
@@ -43,8 +45,14 @@ public class AuditResource {
 
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
-    public Response createEndpoint(@Auth UserInfo userInfo, @Valid AuditCreateDTO auditCreateDTO) {
+    public Response saveAudit(@Auth UserInfo userInfo, @Valid AuditCreateDTO auditCreateDTO) {
         auditService.save(userInfo.getName(), auditCreateDTO);
         return Response.ok().build();
     }
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getAudit(@Auth UserInfo userInfo) {
+        return Response.ok(auditService.getAudit()).build();
+    }
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java
index 785c59b..e3cf50c 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/AuditService.java
@@ -22,8 +22,12 @@ package com.epam.dlab.backendapi.service;
 import com.epam.dlab.backendapi.domain.AuditCreateDTO;
 import com.epam.dlab.backendapi.domain.AuditDTO;
 
+import java.util.List;
+
 public interface AuditService {
     void save(AuditDTO audit);
 
     void save(String user, AuditCreateDTO audit);
+
+    List<AuditDTO> getAudit();
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java
index d35e00f..c2d17e0 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/AuditServiceImpl.java
@@ -26,6 +26,8 @@ import com.epam.dlab.backendapi.domain.AuditDTO;
 import com.epam.dlab.backendapi.service.AuditService;
 import com.google.inject.Inject;
 
+import java.util.List;
+
 public class AuditServiceImpl implements AuditService {
     private final AuditDAO auditDAO;
 
@@ -50,4 +52,9 @@ public class AuditServiceImpl implements AuditService {
 
         auditDAO.save(auditDTO);
     }
+
+    @Override
+    public List<AuditDTO> getAudit() {
+        return auditDAO.getAudit();
+    }
 }


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


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

Posted by of...@apache.org.
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